From 21955002739ec395454da34d7e1560209b450910 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 16 May 2026 22:15:39 +0200 Subject: [PATCH 1/2] feat(diagnostics): split `TraitImplIncorrectSafety` into distinct rustc errors --- crates/hir/src/diagnostics.rs | 46 +++++-- crates/hir/src/lib.rs | 44 +++++- .../handlers/trait_impl_incorrect_safety.rs | 130 +++++++++++++----- crates/ide-diagnostics/src/lib.rs | 6 +- 4 files changed, 174 insertions(+), 52 deletions(-) diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index f3188c9aada5..0d4ec4265aa4 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -146,9 +146,10 @@ diagnostics![AnyDiagnostic<'db> -> PrivateField, RemoveTrailingReturn, RemoveUnnecessaryElse, + SafeImplOfDanglingDrop, + SafeImplOfUnsafeTrait, UnusedMustUse<'db>, ReplaceFilterMapNextWithFindMap, - TraitImplIncorrectSafety, TraitImplMissingAssocItems, TraitImplOrphan, TraitImplRedundantAssocItems, @@ -165,6 +166,9 @@ diagnostics![AnyDiagnostic<'db> -> UnresolvedMethodCall<'db>, UnresolvedModule, UnresolvedIdent, + UnsafeImplOfSafeTrait, + UnsafeInherentImpl, + UnsafeNegativeImpl, UnusedMut, UnusedVariable, GenericArgsProhibited, @@ -495,14 +499,6 @@ pub struct TraitImplOrphan { pub impl_: AstPtr, } -// FIXME: Split this off into the corresponding 4 rustc errors -#[derive(Debug, PartialEq, Eq)] -pub struct TraitImplIncorrectSafety { - pub file_id: HirFileId, - pub impl_: AstPtr, - pub should_be_safe: bool, -} - #[derive(Debug, PartialEq, Eq)] pub struct TraitImplMissingAssocItems { pub file_id: HirFileId, @@ -528,6 +524,38 @@ pub struct RemoveUnnecessaryElse { pub if_expr: InFile>, } +#[derive(Debug)] +pub struct SafeImplOfDanglingDrop { + pub file_id: HirFileId, + pub impl_: AstPtr, +} + +#[derive(Debug)] +pub struct SafeImplOfUnsafeTrait { + pub file_id: HirFileId, + pub trait_: Trait, + pub impl_: AstPtr, +} + +#[derive(Debug)] +pub struct UnsafeImplOfSafeTrait { + pub file_id: HirFileId, + pub trait_: Trait, + pub impl_: AstPtr, +} + +#[derive(Debug)] +pub struct UnsafeInherentImpl { + pub file_id: HirFileId, + pub impl_: AstPtr, +} + +#[derive(Debug)] +pub struct UnsafeNegativeImpl { + pub file_id: HirFileId, + pub impl_: AstPtr, +} + #[derive(Debug)] pub struct UnusedMustUse<'db> { pub expr: InFile, diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index d187763151a2..bfa34375baaa 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -895,13 +895,45 @@ impl Module { match (impl_is_unsafe, trait_is_unsafe, impl_is_negative, drop_maybe_dangle) { // unsafe negative impl - (true, _, true, _) | - // unsafe impl for safe trait - (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()), - // safe impl for unsafe trait - (false, true, false, _) | + (true, _, true, _) => { + acc.push( + UnsafeNegativeImpl { file_id, impl_: ast_id_map.get(loc.id.value) }.into(), + ); + } + + (true, false, _, false) => { + let impl_ = ast_id_map.get(loc.id.value); + + if let Some(trait_) = trait_ { + // unsafe impl of safe trait + acc.push(UnsafeImplOfSafeTrait { trait_, file_id, impl_ }.into()); + } else { + // unsafe inherent impl + acc.push(UnsafeInherentImpl { file_id, impl_ }.into()); + } + } + + // safe impl of unsafe trait + (false, true, false, _) => { + if let Some(trait_) = trait_ { + acc.push( + SafeImplOfUnsafeTrait { + trait_, + file_id, + impl_: ast_id_map.get(loc.id.value), + } + .into(), + ); + } + } + // safe impl of dangling drop - (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: false }.into()), + (false, false, _, true) => { + acc.push( + SafeImplOfDanglingDrop { file_id, impl_: ast_id_map.get(loc.id.value) } + .into(), + ); + } _ => (), }; diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs index 9e7393c89c15..e1270c09f369 100644 --- a/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs +++ b/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs @@ -1,37 +1,95 @@ use hir::InFile; -use syntax::ast; +use syntax::AstNode; -use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity, adjusted_display_range}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_display_range}; -// Diagnostic: trait-impl-incorrect-safety +// Diagnostic: unsafe-inherent-impl // -// Diagnoses incorrect safety annotations of trait impls. -pub(crate) fn trait_impl_incorrect_safety( +// This diagnostic is triggered when an inherent implementation is marked `unsafe` +pub(crate) fn unsafe_inherent_impl( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::TraitImplIncorrectSafety, + d: &hir::UnsafeInherentImpl, ) -> Diagnostic { Diagnostic::new( - DiagnosticCode::Ra("trait-impl-incorrect-safety", Severity::Error), - if d.should_be_safe { - "unsafe impl for safe trait" - } else { - "impl for unsafe trait needs to be unsafe" - }, - adjusted_display_range::( - ctx, - InFile { file_id: d.file_id, value: d.impl_ }, - &|impl_| { - if d.should_be_safe { - Some(match (impl_.unsafe_token(), impl_.impl_token()) { - (None, None) => return None, - (None, Some(t)) | (Some(t), None) => t.text_range(), - (Some(t1), Some(t2)) => t1.text_range().cover(t2.text_range()), - }) - } else { - impl_.impl_token().map(|t| t.text_range()) - } - }, - ), + DiagnosticCode::RustcHardError("E0197"), + "inherent impls cannot be unsafe", + adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + Some((impl_.unsafe_token()?.text_range()).cover(impl_.self_ty()?.syntax().text_range())) + }), + ) + .stable() +} + +// Diagnostic: unsafe-negative-impl +// +// This diagnostic is triggered when a negative implementation is marked `unsafe` +pub(crate) fn unsafe_negative_impl( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::UnsafeNegativeImpl, +) -> Diagnostic { + Diagnostic::new( + DiagnosticCode::RustcHardError("E0198"), + "negative impls cannot be unsafe", + adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + Some((impl_.unsafe_token()?.text_range()).cover(impl_.self_ty()?.syntax().text_range())) + }), + ) + .stable() +} + +// Diagnostic: unsafe-impl-of-safe-trait +// +// This diagnostic is triggered when an implementation of a safe trait is marked `unsafe` +pub(crate) fn unsafe_impl_of_safe_trait( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::UnsafeImplOfSafeTrait, +) -> Diagnostic { + let trait_name = d.trait_.name(ctx.db()); + let trait_name = trait_name.display(ctx.db(), ctx.edition); + + Diagnostic::new( + DiagnosticCode::RustcHardError("E0199"), + format!("implementing the trait `{trait_name}` is not unsafe"), + adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + Some(impl_.unsafe_token()?.text_range().cover(impl_.self_ty()?.syntax().text_range())) + }), + ) + .stable() +} + +// Diagnostic: safe-impl-of-unsafe-trait +// +// This diagnostic is triggered when an implementation of an unsafe trait is missing `unsafe` +pub(crate) fn safe_impl_of_unsafe_trait( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::SafeImplOfUnsafeTrait, +) -> Diagnostic { + let trait_name = d.trait_.name(ctx.db()); + let trait_name = trait_name.display(ctx.db(), ctx.edition); + + Diagnostic::new( + DiagnosticCode::RustcHardError("E0200"), + format!("the trait `{trait_name}` requires an `unsafe impl` declaration"), + adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + Some(impl_.impl_token()?.text_range().cover(impl_.self_ty()?.syntax().text_range())) + }), + ) + .stable() +} + +// Diagnostic: safe-impl-of-dangling-drop +// +// This diagnostic is triggered when an implementation of `Drop` using `#[may_dangle]` is missing `unsafe` +pub(crate) fn safe_impl_of_dangling_drop( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::SafeImplOfDanglingDrop, +) -> Diagnostic { + Diagnostic::new( + DiagnosticCode::RustcHardError("E0569"), + "requires an `unsafe impl` declaration due to `#[may_dangle]` attribute", + adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + Some(impl_.impl_token()?.text_range().cover(impl_.self_ty()?.syntax().text_range())) + }), ) .stable() } @@ -50,10 +108,10 @@ unsafe trait Unsafe {} impl Safe for () {} impl Unsafe for () {} -//^^^^ error: impl for unsafe trait needs to be unsafe +//^^^^^^^^^^^^^^^^^^ error: the trait `Unsafe` requires an `unsafe impl` declaration unsafe impl Safe for () {} -//^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^^^^^^^^^^^^^ error: implementing the trait `Safe` is not unsafe unsafe impl Unsafe for () {} "#, @@ -73,20 +131,20 @@ struct L<'l>; impl Drop for S {} impl<#[may_dangle] T> Drop for S {} -//^^^^ error: impl for unsafe trait needs to be unsafe +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute unsafe impl Drop for S {} -//^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementing the trait `Drop` is not unsafe unsafe impl<#[may_dangle] T> Drop for S {} impl<'l> Drop for L<'l> {} impl<#[may_dangle] 'l> Drop for L<'l> {} -//^^^^ error: impl for unsafe trait needs to be unsafe +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute unsafe impl<'l> Drop for L<'l> {} -//^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementing the trait `Drop` is not unsafe unsafe impl<#[may_dangle] 'l> Drop for L<'l> {} "#, @@ -102,14 +160,14 @@ trait Trait {} impl !Trait for () {} unsafe impl !Trait for () {} -//^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^^^^^^^^^^^^^^^ error: negative impls cannot be unsafe unsafe trait UnsafeTrait {} impl !UnsafeTrait for () {} unsafe impl !UnsafeTrait for () {} -//^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: negative impls cannot be unsafe "#, ); @@ -124,7 +182,7 @@ struct S; impl S {} unsafe impl S {} -//^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^^^ error: inherent impls cannot be unsafe "#, ); } diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index aec68b55c78d..ed4d0aaf64e3 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -494,7 +494,11 @@ pub fn semantic_diagnostics( AnyDiagnostic::PrivateAssocItem(d) => handlers::private_assoc_item::private_assoc_item(&ctx, &d), AnyDiagnostic::PrivateField(d) => handlers::private_field::private_field(&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::SafeImplOfUnsafeTrait(d) => handlers::trait_impl_incorrect_safety::safe_impl_of_unsafe_trait(&ctx, &d), + AnyDiagnostic::SafeImplOfDanglingDrop(d) => handlers::trait_impl_incorrect_safety::safe_impl_of_dangling_drop(&ctx, &d), + AnyDiagnostic::UnsafeImplOfSafeTrait(d) => handlers::trait_impl_incorrect_safety::unsafe_impl_of_safe_trait(&ctx, &d), + AnyDiagnostic::UnsafeInherentImpl(d) => handlers::trait_impl_incorrect_safety::unsafe_inherent_impl(&ctx, &d), + AnyDiagnostic::UnsafeNegativeImpl(d) => handlers::trait_impl_incorrect_safety::unsafe_negative_impl(&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), From 1ead6e1ef79da9ebe2f2b95e211b3f77c48ae857 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 29 May 2026 11:54:08 +0200 Subject: [PATCH 2/2] have an enum variant per error, instead of a whole struct --- crates/hir/src/diagnostics.rs | 38 +++--------- crates/hir/src/lib.rs | 37 +++++++++--- ...ect_safety.rs => impl_incorrect_safety.rs} | 59 +++++++++++++------ crates/ide-diagnostics/src/lib.rs | 8 +-- 4 files changed, 82 insertions(+), 60 deletions(-) rename crates/ide-diagnostics/src/handlers/{trait_impl_incorrect_safety.rs => impl_incorrect_safety.rs} (73%) diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 0d4ec4265aa4..7038709431d0 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -113,6 +113,7 @@ diagnostics![AnyDiagnostic<'db> -> FruInDestructuringAssignment, FunctionalRecordUpdateOnNonStruct, GenericDefaultRefersToSelf, + ImplIncorrectSafety, InactiveCode, IncoherentImpl, IncorrectCase, @@ -146,8 +147,6 @@ diagnostics![AnyDiagnostic<'db> -> PrivateField, RemoveTrailingReturn, RemoveUnnecessaryElse, - SafeImplOfDanglingDrop, - SafeImplOfUnsafeTrait, UnusedMustUse<'db>, ReplaceFilterMapNextWithFindMap, TraitImplMissingAssocItems, @@ -166,9 +165,6 @@ diagnostics![AnyDiagnostic<'db> -> UnresolvedMethodCall<'db>, UnresolvedModule, UnresolvedIdent, - UnsafeImplOfSafeTrait, - UnsafeInherentImpl, - UnsafeNegativeImpl, UnusedMut, UnusedVariable, GenericArgsProhibited, @@ -525,35 +521,19 @@ pub struct RemoveUnnecessaryElse { } #[derive(Debug)] -pub struct SafeImplOfDanglingDrop { +pub struct ImplIncorrectSafety { pub file_id: HirFileId, pub impl_: AstPtr, + pub kind: ImplIncorrectSafetyKind, } #[derive(Debug)] -pub struct SafeImplOfUnsafeTrait { - pub file_id: HirFileId, - pub trait_: Trait, - pub impl_: AstPtr, -} - -#[derive(Debug)] -pub struct UnsafeImplOfSafeTrait { - pub file_id: HirFileId, - pub trait_: Trait, - pub impl_: AstPtr, -} - -#[derive(Debug)] -pub struct UnsafeInherentImpl { - pub file_id: HirFileId, - pub impl_: AstPtr, -} - -#[derive(Debug)] -pub struct UnsafeNegativeImpl { - pub file_id: HirFileId, - pub impl_: AstPtr, +pub enum ImplIncorrectSafetyKind { + UnsafeInherentImpl, + UnsafeNegativeImpl, + UnsafeImplOfSafeTrait(Trait), + SafeImplOfUnsafeTrait(Trait), + SafeImplOfDanglingDrop, } #[derive(Debug)] diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index bfa34375baaa..7f8707ba34a4 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -897,7 +897,12 @@ impl Module { // unsafe negative impl (true, _, true, _) => { acc.push( - UnsafeNegativeImpl { file_id, impl_: ast_id_map.get(loc.id.value) }.into(), + ImplIncorrectSafety { + file_id, + impl_: ast_id_map.get(loc.id.value), + kind: ImplIncorrectSafetyKind::UnsafeNegativeImpl, + } + .into(), ); } @@ -906,10 +911,24 @@ impl Module { if let Some(trait_) = trait_ { // unsafe impl of safe trait - acc.push(UnsafeImplOfSafeTrait { trait_, file_id, impl_ }.into()); + acc.push( + ImplIncorrectSafety { + file_id, + impl_, + kind: ImplIncorrectSafetyKind::UnsafeImplOfSafeTrait(trait_), + } + .into(), + ); } else { // unsafe inherent impl - acc.push(UnsafeInherentImpl { file_id, impl_ }.into()); + acc.push( + ImplIncorrectSafety { + file_id, + impl_, + kind: ImplIncorrectSafetyKind::UnsafeInherentImpl, + } + .into(), + ); } } @@ -917,10 +936,10 @@ impl Module { (false, true, false, _) => { if let Some(trait_) = trait_ { acc.push( - SafeImplOfUnsafeTrait { - trait_, + ImplIncorrectSafety { file_id, impl_: ast_id_map.get(loc.id.value), + kind: ImplIncorrectSafetyKind::SafeImplOfUnsafeTrait(trait_), } .into(), ); @@ -930,8 +949,12 @@ impl Module { // safe impl of dangling drop (false, false, _, true) => { acc.push( - SafeImplOfDanglingDrop { file_id, impl_: ast_id_map.get(loc.id.value) } - .into(), + ImplIncorrectSafety { + file_id, + impl_: ast_id_map.get(loc.id.value), + kind: ImplIncorrectSafetyKind::SafeImplOfDanglingDrop, + } + .into(), ); } _ => (), diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/crates/ide-diagnostics/src/handlers/impl_incorrect_safety.rs similarity index 73% rename from crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs rename to crates/ide-diagnostics/src/handlers/impl_incorrect_safety.rs index e1270c09f369..aad71ecfaec0 100644 --- a/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs +++ b/crates/ide-diagnostics/src/handlers/impl_incorrect_safety.rs @@ -1,96 +1,119 @@ use hir::InFile; -use syntax::AstNode; +use syntax::{AstNode, AstPtr, ast}; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_display_range}; +pub(crate) fn impl_incorrect_safety( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::ImplIncorrectSafety, +) -> Diagnostic { + use hir::ImplIncorrectSafetyKind as Kind; + + let impl_ = InFile { file_id: d.file_id, value: d.impl_ }; + match d.kind { + Kind::UnsafeInherentImpl => unsafe_inherent_impl(ctx, impl_), + Kind::UnsafeNegativeImpl => unsafe_negative_impl(ctx, impl_), + Kind::UnsafeImplOfSafeTrait(trait_) => unsafe_impl_of_safe_trait(ctx, impl_, trait_), + Kind::SafeImplOfUnsafeTrait(trait_) => safe_impl_of_unsafe_trait(ctx, impl_, trait_), + Kind::SafeImplOfDanglingDrop => safe_impl_of_dangling_drop(ctx, impl_), + } +} + // Diagnostic: unsafe-inherent-impl // // This diagnostic is triggered when an inherent implementation is marked `unsafe` -pub(crate) fn unsafe_inherent_impl( +fn unsafe_inherent_impl( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::UnsafeInherentImpl, + impl_: InFile>, ) -> Diagnostic { Diagnostic::new( DiagnosticCode::RustcHardError("E0197"), "inherent impls cannot be unsafe", - adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + adjusted_display_range(ctx, impl_, &|impl_| { Some((impl_.unsafe_token()?.text_range()).cover(impl_.self_ty()?.syntax().text_range())) }), ) + .with_main_node(impl_.map(Into::into)) .stable() } // Diagnostic: unsafe-negative-impl // // This diagnostic is triggered when a negative implementation is marked `unsafe` -pub(crate) fn unsafe_negative_impl( +fn unsafe_negative_impl( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::UnsafeNegativeImpl, + impl_: InFile>, ) -> Diagnostic { Diagnostic::new( DiagnosticCode::RustcHardError("E0198"), "negative impls cannot be unsafe", - adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + adjusted_display_range(ctx, impl_, &|impl_| { Some((impl_.unsafe_token()?.text_range()).cover(impl_.self_ty()?.syntax().text_range())) }), ) + .with_main_node(impl_.map(Into::into)) .stable() } // Diagnostic: unsafe-impl-of-safe-trait // // This diagnostic is triggered when an implementation of a safe trait is marked `unsafe` -pub(crate) fn unsafe_impl_of_safe_trait( +fn unsafe_impl_of_safe_trait( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::UnsafeImplOfSafeTrait, + impl_: InFile>, + trait_: hir::Trait, ) -> Diagnostic { - let trait_name = d.trait_.name(ctx.db()); + let trait_name = trait_.name(ctx.db()); let trait_name = trait_name.display(ctx.db(), ctx.edition); Diagnostic::new( DiagnosticCode::RustcHardError("E0199"), format!("implementing the trait `{trait_name}` is not unsafe"), - adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + adjusted_display_range(ctx, impl_, &|impl_| { Some(impl_.unsafe_token()?.text_range().cover(impl_.self_ty()?.syntax().text_range())) }), ) + .with_main_node(impl_.map(Into::into)) .stable() } // Diagnostic: safe-impl-of-unsafe-trait // // This diagnostic is triggered when an implementation of an unsafe trait is missing `unsafe` -pub(crate) fn safe_impl_of_unsafe_trait( +fn safe_impl_of_unsafe_trait( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::SafeImplOfUnsafeTrait, + impl_: InFile>, + trait_: hir::Trait, ) -> Diagnostic { - let trait_name = d.trait_.name(ctx.db()); + let trait_name = trait_.name(ctx.db()); let trait_name = trait_name.display(ctx.db(), ctx.edition); Diagnostic::new( DiagnosticCode::RustcHardError("E0200"), format!("the trait `{trait_name}` requires an `unsafe impl` declaration"), - adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + adjusted_display_range(ctx, impl_, &|impl_| { Some(impl_.impl_token()?.text_range().cover(impl_.self_ty()?.syntax().text_range())) }), ) + .with_main_node(impl_.map(Into::into)) .stable() } // Diagnostic: safe-impl-of-dangling-drop // // This diagnostic is triggered when an implementation of `Drop` using `#[may_dangle]` is missing `unsafe` -pub(crate) fn safe_impl_of_dangling_drop( +fn safe_impl_of_dangling_drop( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::SafeImplOfDanglingDrop, + impl_: InFile>, ) -> Diagnostic { Diagnostic::new( DiagnosticCode::RustcHardError("E0569"), "requires an `unsafe impl` declaration due to `#[may_dangle]` attribute", - adjusted_display_range(ctx, InFile { file_id: d.file_id, value: d.impl_ }, &|impl_| { + adjusted_display_range(ctx, impl_, &|impl_| { Some(impl_.impl_token()?.text_range().cover(impl_.self_ty()?.syntax().text_range())) }), ) + .with_main_node(impl_.map(Into::into)) .stable() } diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index ed4d0aaf64e3..8279cc2495f7 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -45,6 +45,7 @@ mod handlers { pub(crate) mod functional_record_update_on_non_struct; pub(crate) mod generic_args_prohibited; pub(crate) mod generic_default_refers_to_self; + pub(crate) mod impl_incorrect_safety; pub(crate) mod inactive_code; pub(crate) mod incoherent_impl; pub(crate) mod incorrect_case; @@ -77,7 +78,6 @@ mod handlers { pub(crate) mod remove_trailing_return; pub(crate) mod remove_unnecessary_else; pub(crate) mod replace_filter_map_next_with_find_map; - pub(crate) mod trait_impl_incorrect_safety; pub(crate) mod trait_impl_missing_assoc_item; pub(crate) mod trait_impl_orphan; pub(crate) mod trait_impl_redundant_assoc_item; @@ -448,6 +448,7 @@ pub fn semantic_diagnostics( AnyDiagnostic::ExpectedArrayOrSlicePat(d) => handlers::expected_array_or_slice_pat::expected_array_or_slice_pat(&ctx, &d), AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d), AnyDiagnostic::FunctionalRecordUpdateOnNonStruct(d) => handlers::functional_record_update_on_non_struct::functional_record_update_on_non_struct(&ctx, &d), + AnyDiagnostic::ImplIncorrectSafety(d) => handlers::impl_incorrect_safety::impl_incorrect_safety(&ctx, &d), AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { Some(it) => it, None => continue, @@ -494,11 +495,6 @@ pub fn semantic_diagnostics( AnyDiagnostic::PrivateAssocItem(d) => handlers::private_assoc_item::private_assoc_item(&ctx, &d), AnyDiagnostic::PrivateField(d) => handlers::private_field::private_field(&ctx, &d), AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), - AnyDiagnostic::SafeImplOfUnsafeTrait(d) => handlers::trait_impl_incorrect_safety::safe_impl_of_unsafe_trait(&ctx, &d), - AnyDiagnostic::SafeImplOfDanglingDrop(d) => handlers::trait_impl_incorrect_safety::safe_impl_of_dangling_drop(&ctx, &d), - AnyDiagnostic::UnsafeImplOfSafeTrait(d) => handlers::trait_impl_incorrect_safety::unsafe_impl_of_safe_trait(&ctx, &d), - AnyDiagnostic::UnsafeInherentImpl(d) => handlers::trait_impl_incorrect_safety::unsafe_inherent_impl(&ctx, &d), - AnyDiagnostic::UnsafeNegativeImpl(d) => handlers::trait_impl_incorrect_safety::unsafe_negative_impl(&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),