Skip to content

Commit d18ead5

Browse files
committed
update: make each trait_impl_reduntant_assoc_item into individual diagnostic
1 parent b3ee9fb commit d18ead5

File tree

3 files changed

+65
-32
lines changed

3 files changed

+65
-32
lines changed

crates/hir/src/diagnostics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,5 +316,5 @@ pub struct TraitImplMissingAssocItems {
316316
pub struct TraitImplReduntantAssocItems {
317317
pub file_id: HirFileId,
318318
pub impl_: AstPtr<ast::Impl>,
319-
pub reduntant: Vec<(Name, AssocItem)>,
320-
}
319+
pub assoc_item: (Name, AssocItem),
320+
}

crates/hir/src/lib.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -685,20 +685,21 @@ 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
688+
let reduntant: Vec<_> = impl_assoc_items_scratch
689+
.iter()
690+
.filter(|(id, name)| {
691+
!items.iter().any(|(impl_name, impl_item)| {
692+
discriminant(impl_item) == discriminant(id) && impl_name == name
693+
})
692694
})
693-
})
694-
.map(|(item, name)| (name.clone(), AssocItem::from(*item)))
695-
.collect();
696-
if !reduntant.is_empty() {
695+
.map(|(item, name)| (name.clone(), AssocItem::from(*item)))
696+
.collect();
697+
for (name, assoc_item) in reduntant {
697698
acc.push(
698699
TraitImplReduntantAssocItems {
699700
impl_: ast_id_map.get(node.ast_id()),
700701
file_id,
701-
reduntant,
702+
assoc_item: (name, assoc_item),
702703
}
703704
.into(),
704705
)

crates/ide-diagnostics/src/handlers/trait_impl_reduntant_assoc_item.rs

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use hir::InFile;
2-
use itertools::Itertools;
3-
use syntax::{ast, AstNode};
1+
use hir::{db::ExpandDatabase, Const, Function, HasSource, TypeAlias};
2+
use syntax::ast;
43

5-
use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
4+
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
65

76
// Diagnostic: trait-impl-reduntant-assoc_item
87
//
@@ -11,26 +10,53 @@ pub(crate) fn trait_impl_reduntant_assoc_item(
1110
ctx: &DiagnosticsContext<'_>,
1211
d: &hir::TraitImplReduntantAssocItems,
1312
) -> 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-
});
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 root = ctx.sema.db.parse_or_expand(d.file_id);
18+
let range = root.text_range();
19+
let impl_ = d.impl_.to_node(&root);
20+
let trait_name = if let Some(trait_name) = trait_name(ctx, impl_) {
21+
trait_name
22+
} else {
23+
String::from("{unkown}")
24+
};
25+
26+
let (reduntant_item_name, diagnostic_range) = match assoc_item {
27+
hir::AssocItem::Function(id) => (
28+
format!("`fn {}`", name.display(db)),
29+
Function::from(id).source(db).map(|it| it.syntax().value.text_range()).unwrap_or(range),
30+
),
31+
hir::AssocItem::Const(id) => (
32+
format!("`const {}`", name.display(db)),
33+
Const::from(id).source(db).map(|it| it.syntax().value.text_range()).unwrap_or(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(range),
41+
),
42+
};
43+
2344
Diagnostic::new(
2445
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-
),
46+
format!("{reduntant_item_name} is not a member of trait `{trait_name}`"),
47+
diagnostic_range,
3148
)
3249
}
3350

51+
fn trait_name(ctx: &DiagnosticsContext<'_>, impl_: ast::Impl) -> Option<String> {
52+
if let ast::Type::PathType(trait_path) = impl_.trait_()? {
53+
let trait_type = ctx.sema.resolve_trait(&trait_path.path()?)?;
54+
Some(trait_type.name(ctx.sema.db).as_text()?.to_string())
55+
} else {
56+
None
57+
}
58+
}
59+
3460
#[cfg(test)]
3561
mod tests {
3662
use crate::tests::check_diagnostics;
@@ -40,14 +66,20 @@ mod tests {
4066
check_diagnostics(
4167
r#"
4268
trait Marker {
69+
const FLAG: bool = false;
4370
fn boo();
71+
fn foo () {}
4472
}
4573
struct Foo;
4674
impl Marker for Foo {
47-
//^^^^^^ error: `type T`, `const FLAG`, `fn bar` is not a member of trait
4875
type T = i32;
49-
const FLAG: bool = false;
76+
//^^^^^^^^^^^^^ error: `type T` is not a member of trait `Marker`
77+
78+
const FLAG: bool = true;
79+
5080
fn bar() {}
81+
//^^^^^^^^^^^ error: `fn bar` is not a member of trait `Marker`
82+
5183
fn boo() {}
5284
}
5385
"#,

0 commit comments

Comments
 (0)