about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-07 13:24:57 +0000
committerbors <bors@rust-lang.org>2023-12-07 13:24:57 +0000
commit421a0a4ff4a0619a66aceded8f7040444723c78d (patch)
tree988605b0c8ccaf9780098fb54b5b2035cca281ff
parent07d3128de2bb012650f6324c7328b1e35ab6cd24 (diff)
parentfbe494a10613f8fff8c03fa81b6751740a327068 (diff)
downloadrust-421a0a4ff4a0619a66aceded8f7040444723c78d.tar.gz
rust-421a0a4ff4a0619a66aceded8f7040444723c78d.zip
Auto merge of #15990 - Young-Flash:trait_impl_reduntant_assoc_item, r=Veykril
feat: add trait_impl_reduntant_assoc_item diagnostic

part of https://github.com/rust-lang/rust-analyzer/issues/15958, will try to add quickfix for the diagnostic if this PR is ok with you guys
-rw-r--r--crates/hir/src/diagnostics.rs11
-rw-r--r--crates/hir/src/lib.rs20
-rw-r--r--crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs79
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
4 files changed, 111 insertions, 1 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index cf9a2b73d9b..1cb36f9b021 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -12,7 +12,7 @@ use hir_def::path::ModPath;
 use hir_expand::{name::Name, HirFileId, InFile};
 use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
 
-use crate::{AssocItem, Field, Local, MacroKind, Type};
+use crate::{AssocItem, Field, Local, MacroKind, Trait, Type};
 
 macro_rules! diagnostics {
     ($($diag:ident,)*) => {
@@ -55,6 +55,7 @@ diagnostics![
     ReplaceFilterMapNextWithFindMap,
     TraitImplIncorrectSafety,
     TraitImplMissingAssocItems,
+    TraitImplRedundantAssocItems,
     TraitImplOrphan,
     TypedHole,
     TypeMismatch,
@@ -310,3 +311,11 @@ pub struct TraitImplMissingAssocItems {
     pub impl_: AstPtr<ast::Impl>,
     pub missing: Vec<(Name, AssocItem)>,
 }
+
+#[derive(Debug, PartialEq, Eq)]
+pub struct TraitImplRedundantAssocItems {
+    pub file_id: HirFileId,
+    pub trait_: Trait,
+    pub impl_: AstPtr<ast::Impl>,
+    pub assoc_item: (Name, AssocItem),
+}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 4a0c384e8a3..5137bff055a 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -693,6 +693,26 @@ impl Module {
                     },
                 ));
 
+                let redundant = impl_assoc_items_scratch
+                    .iter()
+                    .filter(|(id, name)| {
+                        !items.iter().any(|(impl_name, impl_item)| {
+                            discriminant(impl_item) == discriminant(id) && impl_name == name
+                        })
+                    })
+                    .map(|(item, name)| (name.clone(), AssocItem::from(*item)));
+                for (name, assoc_item) in redundant {
+                    acc.push(
+                        TraitImplRedundantAssocItems {
+                            trait_,
+                            file_id,
+                            impl_: ast_id_map.get(node.ast_id()),
+                            assoc_item: (name, assoc_item),
+                        }
+                        .into(),
+                    )
+                }
+
                 let missing: Vec<_> = required_items
                     .filter(|(name, id)| {
                         !impl_assoc_items_scratch.iter().any(|(impl_item, impl_name)| {
diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
new file mode 100644
index 00000000000..82001439146
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -0,0 +1,79 @@
+use hir::{Const, Function, HasSource, TypeAlias};
+use ide_db::base_db::FileRange;
+
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: trait-impl-redundant-assoc_item
+//
+// Diagnoses redundant trait items in a trait impl.
+pub(crate) fn trait_impl_redundant_assoc_item(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::TraitImplRedundantAssocItems,
+) -> Diagnostic {
+    let name = d.assoc_item.0.clone();
+    let assoc_item = d.assoc_item.1;
+    let db = ctx.sema.db;
+
+    let default_range = d.impl_.syntax_node_ptr().text_range();
+    let trait_name = d.trait_.name(db).to_smol_str();
+
+    let (redundant_item_name, diagnostic_range) = match assoc_item {
+        hir::AssocItem::Function(id) => (
+            format!("`fn {}`", name.display(db)),
+            Function::from(id)
+                .source(db)
+                .map(|it| it.syntax().value.text_range())
+                .unwrap_or(default_range),
+        ),
+        hir::AssocItem::Const(id) => (
+            format!("`const {}`", name.display(db)),
+            Const::from(id)
+                .source(db)
+                .map(|it| it.syntax().value.text_range())
+                .unwrap_or(default_range),
+        ),
+        hir::AssocItem::TypeAlias(id) => (
+            format!("`type {}`", name.display(db)),
+            TypeAlias::from(id)
+                .source(db)
+                .map(|it| it.syntax().value.text_range())
+                .unwrap_or(default_range),
+        ),
+    };
+
+    Diagnostic::new(
+        DiagnosticCode::RustcHardError("E0407"),
+        format!("{redundant_item_name} is not a member of trait `{trait_name}`"),
+        FileRange { file_id: d.file_id.file_id().unwrap(), range: diagnostic_range },
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_diagnostics;
+
+    #[test]
+    fn trait_with_default_value() {
+        check_diagnostics(
+            r#"
+trait Marker {
+    const FLAG: bool = false;
+    fn boo();
+    fn foo () {}
+}
+struct Foo;
+impl Marker for Foo {
+    type T = i32;
+  //^^^^^^^^^^^^^ error: `type T` is not a member of trait `Marker`
+
+    const FLAG: bool = true;
+
+    fn bar() {}
+  //^^^^^^^^^^^ error: `fn bar` is not a member of trait `Marker`
+
+    fn boo() {}
+}
+            "#,
+        )
+    }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 35272e87264..6cfd5f18320 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -47,6 +47,7 @@ mod handlers {
     pub(crate) mod trait_impl_orphan;
     pub(crate) mod trait_impl_incorrect_safety;
     pub(crate) mod trait_impl_missing_assoc_item;
+    pub(crate) mod trait_impl_redundant_assoc_item;
     pub(crate) mod typed_hole;
     pub(crate) mod type_mismatch;
     pub(crate) mod unimplemented_builtin_macro;
@@ -364,6 +365,7 @@ pub fn diagnostics(
             AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
             AnyDiagnostic::TraitImplIncorrectSafety(d) => handlers::trait_impl_incorrect_safety::trait_impl_incorrect_safety(&ctx, &d),
             AnyDiagnostic::TraitImplMissingAssocItems(d) => handlers::trait_impl_missing_assoc_item::trait_impl_missing_assoc_item(&ctx, &d),
+            AnyDiagnostic::TraitImplRedundantAssocItems(d) => handlers::trait_impl_redundant_assoc_item::trait_impl_redundant_assoc_item(&ctx, &d),
             AnyDiagnostic::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d),
             AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d),
             AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),