Skip to content

Commit b3ee9fb

Browse files
committed
feat: add trait_impl_reduntant_assoc_item diagnostic
1 parent 2ee17bc commit b3ee9fb

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed

crates/hir/src/diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ diagnostics![
5555
ReplaceFilterMapNextWithFindMap,
5656
TraitImplIncorrectSafety,
5757
TraitImplMissingAssocItems,
58+
TraitImplReduntantAssocItems,
5859
TraitImplOrphan,
5960
TypedHole,
6061
TypeMismatch,
@@ -310,3 +311,10 @@ 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 TraitImplReduntantAssocItems {
317+
pub file_id: HirFileId,
318+
pub impl_: AstPtr<ast::Impl>,
319+
pub reduntant: Vec<(Name, AssocItem)>,
320+
}

crates/hir/src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,25 @@ impl Module {
685685
},
686686
));
687687

688+
let reduntant: Vec<_> = impl_assoc_items_scratch.iter()
689+
.filter(|(id, name)| {
690+
!required_items.clone().any(|(impl_name, impl_item)| {
691+
discriminant(impl_item) == discriminant(id) && impl_name == name
692+
})
693+
})
694+
.map(|(item, name)| (name.clone(), AssocItem::from(*item)))
695+
.collect();
696+
if !reduntant.is_empty() {
697+
acc.push(
698+
TraitImplReduntantAssocItems {
699+
impl_: ast_id_map.get(node.ast_id()),
700+
file_id,
701+
reduntant,
702+
}
703+
.into(),
704+
)
705+
}
706+
688707
let missing: Vec<_> = required_items
689708
.filter(|(name, id)| {
690709
!impl_assoc_items_scratch.iter().any(|(impl_item, impl_name)| {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use hir::InFile;
2+
use itertools::Itertools;
3+
use syntax::{ast, AstNode};
4+
5+
use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
6+
7+
// Diagnostic: trait-impl-reduntant-assoc_item
8+
//
9+
// Diagnoses reduntant trait items in a trait impl.
10+
pub(crate) fn trait_impl_reduntant_assoc_item(
11+
ctx: &DiagnosticsContext<'_>,
12+
d: &hir::TraitImplReduntantAssocItems,
13+
) -> Diagnostic {
14+
let reduntant = d.reduntant.iter().format_with(", ", |(name, item), f| {
15+
f(&match *item {
16+
hir::AssocItem::Function(_) => "`fn ",
17+
hir::AssocItem::Const(_) => "`const ",
18+
hir::AssocItem::TypeAlias(_) => "`type ",
19+
})?;
20+
f(&name.display(ctx.sema.db))?;
21+
f(&"`")
22+
});
23+
Diagnostic::new(
24+
DiagnosticCode::RustcHardError("E0407"),
25+
format!("{reduntant} is not a member of trait"),
26+
adjusted_display_range::<ast::Impl>(
27+
ctx,
28+
InFile { file_id: d.file_id, value: d.impl_.syntax_node_ptr() },
29+
&|impl_| impl_.trait_().map(|t| t.syntax().text_range()),
30+
),
31+
)
32+
}
33+
34+
#[cfg(test)]
35+
mod tests {
36+
use crate::tests::check_diagnostics;
37+
38+
#[test]
39+
fn trait_with_default_value() {
40+
check_diagnostics(
41+
r#"
42+
trait Marker {
43+
fn boo();
44+
}
45+
struct Foo;
46+
impl Marker for Foo {
47+
//^^^^^^ error: `type T`, `const FLAG`, `fn bar` is not a member of trait
48+
type T = i32;
49+
const FLAG: bool = false;
50+
fn bar() {}
51+
fn boo() {}
52+
}
53+
"#,
54+
)
55+
}
56+
}

crates/ide-diagnostics/src/lib.rs

Lines changed: 2 additions & 0 deletions
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_reduntant_assoc_item;
5051
pub(crate) mod typed_hole;
5152
pub(crate) mod type_mismatch;
5253
pub(crate) mod unimplemented_builtin_macro;
@@ -363,6 +364,7 @@ pub fn diagnostics(
363364
AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
364365
AnyDiagnostic::TraitImplIncorrectSafety(d) => handlers::trait_impl_incorrect_safety::trait_impl_incorrect_safety(&ctx, &d),
365366
AnyDiagnostic::TraitImplMissingAssocItems(d) => handlers::trait_impl_missing_assoc_item::trait_impl_missing_assoc_item(&ctx, &d),
367+
AnyDiagnostic::TraitImplReduntantAssocItems(d) => handlers::trait_impl_reduntant_assoc_item::trait_impl_reduntant_assoc_item(&ctx, &d),
366368
AnyDiagnostic::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d),
367369
AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d),
368370
AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),

0 commit comments

Comments
 (0)