mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
update: make each trait_impl_reduntant_assoc_item into individual diagnostic
This commit is contained in:
parent
5d84edd430
commit
861e47431b
@ -12,7 +12,7 @@ use hir_def::path::ModPath;
|
|||||||
use hir_expand::{name::Name, HirFileId, InFile};
|
use hir_expand::{name::Name, HirFileId, InFile};
|
||||||
use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
|
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 {
|
macro_rules! diagnostics {
|
||||||
($($diag:ident,)*) => {
|
($($diag:ident,)*) => {
|
||||||
@ -55,7 +55,7 @@ diagnostics![
|
|||||||
ReplaceFilterMapNextWithFindMap,
|
ReplaceFilterMapNextWithFindMap,
|
||||||
TraitImplIncorrectSafety,
|
TraitImplIncorrectSafety,
|
||||||
TraitImplMissingAssocItems,
|
TraitImplMissingAssocItems,
|
||||||
TraitImplReduntantAssocItems,
|
TraitImplRedundantAssocItems,
|
||||||
TraitImplOrphan,
|
TraitImplOrphan,
|
||||||
TypedHole,
|
TypedHole,
|
||||||
TypeMismatch,
|
TypeMismatch,
|
||||||
@ -313,8 +313,8 @@ pub struct TraitImplMissingAssocItems {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct TraitImplReduntantAssocItems {
|
pub struct TraitImplRedundantAssocItems {
|
||||||
pub file_id: HirFileId,
|
pub file_id: HirFileId,
|
||||||
pub impl_: AstPtr<ast::Impl>,
|
pub trait_: Trait,
|
||||||
pub reduntant: Vec<(Name, AssocItem)>,
|
pub assoc_item: (Name, AssocItem),
|
||||||
}
|
}
|
@ -693,20 +693,20 @@ impl Module {
|
|||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
let reduntant: Vec<_> = impl_assoc_items_scratch.iter()
|
let redundant = impl_assoc_items_scratch
|
||||||
|
.iter()
|
||||||
.filter(|(id, name)| {
|
.filter(|(id, name)| {
|
||||||
!required_items.clone().any(|(impl_name, impl_item)| {
|
!items.iter().any(|(impl_name, impl_item)| {
|
||||||
discriminant(impl_item) == discriminant(id) && impl_name == name
|
discriminant(impl_item) == discriminant(id) && impl_name == name
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map(|(item, name)| (name.clone(), AssocItem::from(*item)))
|
.map(|(item, name)| (name.clone(), AssocItem::from(*item)));
|
||||||
.collect();
|
for (name, assoc_item) in redundant {
|
||||||
if !reduntant.is_empty() {
|
|
||||||
acc.push(
|
acc.push(
|
||||||
TraitImplReduntantAssocItems {
|
TraitImplRedundantAssocItems {
|
||||||
impl_: ast_id_map.get(node.ast_id()),
|
trait_,
|
||||||
file_id,
|
file_id,
|
||||||
reduntant,
|
assoc_item: (name, assoc_item),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
use hir::{db::ExpandDatabase, Const, Function, HasSource, TypeAlias};
|
||||||
|
|
||||||
|
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 range = db.parse_or_expand(d.file_id).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(range),
|
||||||
|
),
|
||||||
|
hir::AssocItem::Const(id) => (
|
||||||
|
format!("`const {}`", name.display(db)),
|
||||||
|
Const::from(id).source(db).map(|it| it.syntax().value.text_range()).unwrap_or(range),
|
||||||
|
),
|
||||||
|
hir::AssocItem::TypeAlias(id) => (
|
||||||
|
format!("`type {}`", name.display(db)),
|
||||||
|
TypeAlias::from(id)
|
||||||
|
.source(db)
|
||||||
|
.map(|it| it.syntax().value.text_range())
|
||||||
|
.unwrap_or(range),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
Diagnostic::new(
|
||||||
|
DiagnosticCode::RustcHardError("E0407"),
|
||||||
|
format!("{redundant_item_name} is not a member of trait `{trait_name}`"),
|
||||||
|
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() {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,56 +0,0 @@
|
|||||||
use hir::InFile;
|
|
||||||
use itertools::Itertools;
|
|
||||||
use syntax::{ast, AstNode};
|
|
||||||
|
|
||||||
use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
|
|
||||||
|
|
||||||
// Diagnostic: trait-impl-reduntant-assoc_item
|
|
||||||
//
|
|
||||||
// Diagnoses reduntant trait items in a trait impl.
|
|
||||||
pub(crate) fn trait_impl_reduntant_assoc_item(
|
|
||||||
ctx: &DiagnosticsContext<'_>,
|
|
||||||
d: &hir::TraitImplReduntantAssocItems,
|
|
||||||
) -> Diagnostic {
|
|
||||||
let reduntant = d.reduntant.iter().format_with(", ", |(name, item), f| {
|
|
||||||
f(&match *item {
|
|
||||||
hir::AssocItem::Function(_) => "`fn ",
|
|
||||||
hir::AssocItem::Const(_) => "`const ",
|
|
||||||
hir::AssocItem::TypeAlias(_) => "`type ",
|
|
||||||
})?;
|
|
||||||
f(&name.display(ctx.sema.db))?;
|
|
||||||
f(&"`")
|
|
||||||
});
|
|
||||||
Diagnostic::new(
|
|
||||||
DiagnosticCode::RustcHardError("E0407"),
|
|
||||||
format!("{reduntant} is not a member of trait"),
|
|
||||||
adjusted_display_range::<ast::Impl>(
|
|
||||||
ctx,
|
|
||||||
InFile { file_id: d.file_id, value: d.impl_.syntax_node_ptr() },
|
|
||||||
&|impl_| impl_.trait_().map(|t| t.syntax().text_range()),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::tests::check_diagnostics;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn trait_with_default_value() {
|
|
||||||
check_diagnostics(
|
|
||||||
r#"
|
|
||||||
trait Marker {
|
|
||||||
fn boo();
|
|
||||||
}
|
|
||||||
struct Foo;
|
|
||||||
impl Marker for Foo {
|
|
||||||
//^^^^^^ error: `type T`, `const FLAG`, `fn bar` is not a member of trait
|
|
||||||
type T = i32;
|
|
||||||
const FLAG: bool = false;
|
|
||||||
fn bar() {}
|
|
||||||
fn boo() {}
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -47,7 +47,7 @@ mod handlers {
|
|||||||
pub(crate) mod trait_impl_orphan;
|
pub(crate) mod trait_impl_orphan;
|
||||||
pub(crate) mod trait_impl_incorrect_safety;
|
pub(crate) mod trait_impl_incorrect_safety;
|
||||||
pub(crate) mod trait_impl_missing_assoc_item;
|
pub(crate) mod trait_impl_missing_assoc_item;
|
||||||
pub(crate) mod trait_impl_reduntant_assoc_item;
|
pub(crate) mod trait_impl_redundant_assoc_item;
|
||||||
pub(crate) mod typed_hole;
|
pub(crate) mod typed_hole;
|
||||||
pub(crate) mod type_mismatch;
|
pub(crate) mod type_mismatch;
|
||||||
pub(crate) mod unimplemented_builtin_macro;
|
pub(crate) mod unimplemented_builtin_macro;
|
||||||
@ -365,7 +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::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::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::TraitImplMissingAssocItems(d) => handlers::trait_impl_missing_assoc_item::trait_impl_missing_assoc_item(&ctx, &d),
|
||||||
AnyDiagnostic::TraitImplReduntantAssocItems(d) => handlers::trait_impl_reduntant_assoc_item::trait_impl_reduntant_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::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d),
|
||||||
AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d),
|
AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d),
|
||||||
AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
|
AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user