Skip to content

Commit 421a0a4

Browse files
committed
Auto merge of rust-lang#15990 - Young-Flash:trait_impl_reduntant_assoc_item, r=Veykril
feat: add trait_impl_reduntant_assoc_item diagnostic part of rust-lang/rust-analyzer#15958, will try to add quickfix for the diagnostic if this PR is ok with you guys
2 parents 07d3128 + fbe494a commit 421a0a4

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

crates/hir/src/diagnostics.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use hir_def::path::ModPath;
1212
use hir_expand::{name::Name, HirFileId, InFile};
1313
use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
1414

15-
use crate::{AssocItem, Field, Local, MacroKind, Type};
15+
use crate::{AssocItem, Field, Local, MacroKind, Trait, Type};
1616

1717
macro_rules! diagnostics {
1818
($($diag:ident,)*) => {
@@ -55,6 +55,7 @@ diagnostics![
5555
ReplaceFilterMapNextWithFindMap,
5656
TraitImplIncorrectSafety,
5757
TraitImplMissingAssocItems,
58+
TraitImplRedundantAssocItems,
5859
TraitImplOrphan,
5960
TypedHole,
6061
TypeMismatch,
@@ -310,3 +311,11 @@ pub struct TraitImplMissingAssocItems {
310311
pub impl_: AstPtr<ast::Impl>,
311312
pub missing: Vec<(Name, AssocItem)>,
312313
}
314+
315+
#[derive(Debug, PartialEq, Eq)]
316+
pub struct TraitImplRedundantAssocItems {
317+
pub file_id: HirFileId,
318+
pub trait_: Trait,
319+
pub impl_: AstPtr<ast::Impl>,
320+
pub assoc_item: (Name, AssocItem),
321+
}

crates/hir/src/lib.rs

+20
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,26 @@ impl Module {
693693
},
694694
));
695695

696+
let redundant = impl_assoc_items_scratch
697+
.iter()
698+
.filter(|(id, name)| {
699+
!items.iter().any(|(impl_name, impl_item)| {
700+
discriminant(impl_item) == discriminant(id) && impl_name == name
701+
})
702+
})
703+
.map(|(item, name)| (name.clone(), AssocItem::from(*item)));
704+
for (name, assoc_item) in redundant {
705+
acc.push(
706+
TraitImplRedundantAssocItems {
707+
trait_,
708+
file_id,
709+
impl_: ast_id_map.get(node.ast_id()),
710+
assoc_item: (name, assoc_item),
711+
}
712+
.into(),
713+
)
714+
}
715+
696716
let missing: Vec<_> = required_items
697717
.filter(|(name, id)| {
698718
!impl_assoc_items_scratch.iter().any(|(impl_item, impl_name)| {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use hir::{Const, Function, HasSource, TypeAlias};
2+
use ide_db::base_db::FileRange;
3+
4+
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
5+
6+
// Diagnostic: trait-impl-redundant-assoc_item
7+
//
8+
// Diagnoses redundant trait items in a trait impl.
9+
pub(crate) fn trait_impl_redundant_assoc_item(
10+
ctx: &DiagnosticsContext<'_>,
11+
d: &hir::TraitImplRedundantAssocItems,
12+
) -> Diagnostic {
13+
let name = d.assoc_item.0.clone();
14+
let assoc_item = d.assoc_item.1;
15+
let db = ctx.sema.db;
16+
17+
let default_range = d.impl_.syntax_node_ptr().text_range();
18+
let trait_name = d.trait_.name(db).to_smol_str();
19+
20+
let (redundant_item_name, diagnostic_range) = match assoc_item {
21+
hir::AssocItem::Function(id) => (
22+
format!("`fn {}`", name.display(db)),
23+
Function::from(id)
24+
.source(db)
25+
.map(|it| it.syntax().value.text_range())
26+
.unwrap_or(default_range),
27+
),
28+
hir::AssocItem::Const(id) => (
29+
format!("`const {}`", name.display(db)),
30+
Const::from(id)
31+
.source(db)
32+
.map(|it| it.syntax().value.text_range())
33+
.unwrap_or(default_range),
34+
),
35+
hir::AssocItem::TypeAlias(id) => (
36+
format!("`type {}`", name.display(db)),
37+
TypeAlias::from(id)
38+
.source(db)
39+
.map(|it| it.syntax().value.text_range())
40+
.unwrap_or(default_range),
41+
),
42+
};
43+
44+
Diagnostic::new(
45+
DiagnosticCode::RustcHardError("E0407"),
46+
format!("{redundant_item_name} is not a member of trait `{trait_name}`"),
47+
FileRange { file_id: d.file_id.file_id().unwrap(), range: diagnostic_range },
48+
)
49+
}
50+
51+
#[cfg(test)]
52+
mod tests {
53+
use crate::tests::check_diagnostics;
54+
55+
#[test]
56+
fn trait_with_default_value() {
57+
check_diagnostics(
58+
r#"
59+
trait Marker {
60+
const FLAG: bool = false;
61+
fn boo();
62+
fn foo () {}
63+
}
64+
struct Foo;
65+
impl Marker for Foo {
66+
type T = i32;
67+
//^^^^^^^^^^^^^ error: `type T` is not a member of trait `Marker`
68+
69+
const FLAG: bool = true;
70+
71+
fn bar() {}
72+
//^^^^^^^^^^^ error: `fn bar` is not a member of trait `Marker`
73+
74+
fn boo() {}
75+
}
76+
"#,
77+
)
78+
}
79+
}

crates/ide-diagnostics/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ mod handlers {
4747
pub(crate) mod trait_impl_orphan;
4848
pub(crate) mod trait_impl_incorrect_safety;
4949
pub(crate) mod trait_impl_missing_assoc_item;
50+
pub(crate) mod trait_impl_redundant_assoc_item;
5051
pub(crate) mod typed_hole;
5152
pub(crate) mod type_mismatch;
5253
pub(crate) mod unimplemented_builtin_macro;
@@ -364,6 +365,7 @@ pub fn diagnostics(
364365
AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
365366
AnyDiagnostic::TraitImplIncorrectSafety(d) => handlers::trait_impl_incorrect_safety::trait_impl_incorrect_safety(&ctx, &d),
366367
AnyDiagnostic::TraitImplMissingAssocItems(d) => handlers::trait_impl_missing_assoc_item::trait_impl_missing_assoc_item(&ctx, &d),
368+
AnyDiagnostic::TraitImplRedundantAssocItems(d) => handlers::trait_impl_redundant_assoc_item::trait_impl_redundant_assoc_item(&ctx, &d),
367369
AnyDiagnostic::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d),
368370
AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d),
369371
AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),

0 commit comments

Comments
 (0)