ide_diagnostics/handlers/
trait_impl_incorrect_safety.rsuse hir::InFile;
use syntax::ast;
use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
pub(crate) fn trait_impl_incorrect_safety(
ctx: &DiagnosticsContext<'_>,
d: &hir::TraitImplIncorrectSafety,
) -> 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::<ast::Impl>(
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())
}
},
),
)
}
#[cfg(test)]
mod tests {
use crate::tests::check_diagnostics;
#[test]
fn simple() {
check_diagnostics(
r#"
trait Safe {}
unsafe trait Unsafe {}
impl Safe for () {}
impl Unsafe for () {}
//^^^^ error: impl for unsafe trait needs to be unsafe
unsafe impl Safe for () {}
//^^^^^^^^^^^ error: unsafe impl for safe trait
unsafe impl Unsafe for () {}
"#,
);
}
#[test]
fn drop_may_dangle() {
check_diagnostics(
r#"
#[lang = "drop"]
trait Drop {}
struct S<T>;
struct L<'l>;
impl<T> Drop for S<T> {}
impl<#[may_dangle] T> Drop for S<T> {}
//^^^^ error: impl for unsafe trait needs to be unsafe
unsafe impl<T> Drop for S<T> {}
//^^^^^^^^^^^ error: unsafe impl for safe trait
unsafe impl<#[may_dangle] T> Drop for S<T> {}
impl<'l> Drop for L<'l> {}
impl<#[may_dangle] 'l> Drop for L<'l> {}
//^^^^ error: impl for unsafe trait needs to be unsafe
unsafe impl<'l> Drop for L<'l> {}
//^^^^^^^^^^^ error: unsafe impl for safe trait
unsafe impl<#[may_dangle] 'l> Drop for L<'l> {}
"#,
);
}
#[test]
fn negative() {
check_diagnostics(
r#"
trait Trait {}
impl !Trait for () {}
unsafe impl !Trait for () {}
//^^^^^^^^^^^ error: unsafe impl for safe trait
unsafe trait UnsafeTrait {}
impl !UnsafeTrait for () {}
unsafe impl !UnsafeTrait for () {}
//^^^^^^^^^^^ error: unsafe impl for safe trait
"#,
);
}
#[test]
fn inherent() {
check_diagnostics(
r#"
struct S;
impl S {}
unsafe impl S {}
//^^^^^^^^^^^ error: unsafe impl for safe trait
"#,
);
}
}