ide_diagnostics/handlers/
trait_impl_incorrect_safety.rs

1use hir::InFile;
2use syntax::ast;
3
4use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity, adjusted_display_range};
5
6// Diagnostic: trait-impl-incorrect-safety
7//
8// Diagnoses incorrect safety annotations of trait impls.
9pub(crate) fn trait_impl_incorrect_safety(
10    ctx: &DiagnosticsContext<'_>,
11    d: &hir::TraitImplIncorrectSafety,
12) -> Diagnostic {
13    Diagnostic::new(
14        DiagnosticCode::Ra("trait-impl-incorrect-safety", Severity::Error),
15        if d.should_be_safe {
16            "unsafe impl for safe trait"
17        } else {
18            "impl for unsafe trait needs to be unsafe"
19        },
20        adjusted_display_range::<ast::Impl>(
21            ctx,
22            InFile { file_id: d.file_id, value: d.impl_ },
23            &|impl_| {
24                if d.should_be_safe {
25                    Some(match (impl_.unsafe_token(), impl_.impl_token()) {
26                        (None, None) => return None,
27                        (None, Some(t)) | (Some(t), None) => t.text_range(),
28                        (Some(t1), Some(t2)) => t1.text_range().cover(t2.text_range()),
29                    })
30                } else {
31                    impl_.impl_token().map(|t| t.text_range())
32                }
33            },
34        ),
35    )
36    .stable()
37}
38
39#[cfg(test)]
40mod tests {
41    use crate::tests::check_diagnostics;
42
43    #[test]
44    fn simple() {
45        check_diagnostics(
46            r#"
47trait Safe {}
48unsafe trait Unsafe {}
49
50  impl Safe for () {}
51
52  impl Unsafe for () {}
53//^^^^  error: impl for unsafe trait needs to be unsafe
54
55  unsafe impl Safe for () {}
56//^^^^^^^^^^^ error: unsafe impl for safe trait
57
58  unsafe impl Unsafe for () {}
59"#,
60        );
61    }
62
63    #[test]
64    fn drop_may_dangle() {
65        check_diagnostics(
66            r#"
67#[lang = "drop"]
68trait Drop {}
69struct S<T>;
70struct L<'l>;
71
72  impl<T> Drop for S<T> {}
73
74  impl<#[may_dangle] T> Drop for S<T> {}
75//^^^^ error: impl for unsafe trait needs to be unsafe
76
77  unsafe impl<T> Drop for S<T> {}
78//^^^^^^^^^^^ error: unsafe impl for safe trait
79
80  unsafe impl<#[may_dangle] T> Drop for S<T> {}
81
82  impl<'l> Drop for L<'l> {}
83
84  impl<#[may_dangle] 'l> Drop for L<'l> {}
85//^^^^ error: impl for unsafe trait needs to be unsafe
86
87  unsafe impl<'l> Drop for L<'l> {}
88//^^^^^^^^^^^ error: unsafe impl for safe trait
89
90  unsafe impl<#[may_dangle] 'l> Drop for L<'l> {}
91"#,
92        );
93    }
94
95    #[test]
96    fn negative() {
97        check_diagnostics(
98            r#"
99trait Trait {}
100
101  impl !Trait for () {}
102
103  unsafe impl !Trait for () {}
104//^^^^^^^^^^^ error: unsafe impl for safe trait
105
106unsafe trait UnsafeTrait {}
107
108  impl !UnsafeTrait for () {}
109
110  unsafe impl !UnsafeTrait for () {}
111//^^^^^^^^^^^ error: unsafe impl for safe trait
112
113"#,
114        );
115    }
116
117    #[test]
118    fn inherent() {
119        check_diagnostics(
120            r#"
121struct S;
122
123  impl S {}
124
125  unsafe impl S {}
126//^^^^^^^^^^^ error: unsafe impl for safe trait
127"#,
128        );
129    }
130
131    #[test]
132    fn unsafe_unresolved_trait() {
133        check_diagnostics(
134            r#"
135unsafe impl TestTrait for u32 {}
136        "#,
137        );
138    }
139}