diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 86 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/missing_unsafe.rs | 101 |
2 files changed, 103 insertions, 84 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index e8f22c889..67390345f 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -8,6 +8,7 @@ mod break_outside_of_loop; | |||
8 | mod inactive_code; | 8 | mod inactive_code; |
9 | mod macro_error; | 9 | mod macro_error; |
10 | mod missing_fields; | 10 | mod missing_fields; |
11 | mod missing_unsafe; | ||
11 | mod no_such_field; | 12 | mod no_such_field; |
12 | mod unimplemented_builtin_macro; | 13 | mod unimplemented_builtin_macro; |
13 | mod unresolved_extern_crate; | 14 | mod unresolved_extern_crate; |
@@ -222,6 +223,7 @@ pub(crate) fn diagnostics( | |||
222 | AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d), | 223 | AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d), |
223 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), | 224 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), |
224 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), | 225 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), |
226 | AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), | ||
225 | AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), | 227 | AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), |
226 | AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), | 228 | AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), |
227 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), | 229 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), |
@@ -713,90 +715,6 @@ mod foo; | |||
713 | ); | 715 | ); |
714 | } | 716 | } |
715 | 717 | ||
716 | #[test] | ||
717 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
718 | check_diagnostics( | ||
719 | r#" | ||
720 | fn main() { | ||
721 | let x = &5 as *const usize; | ||
722 | unsafe { let y = *x; } | ||
723 | let z = *x; | ||
724 | } //^^ This operation is unsafe and requires an unsafe function or block | ||
725 | "#, | ||
726 | ) | ||
727 | } | ||
728 | |||
729 | #[test] | ||
730 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
731 | check_diagnostics( | ||
732 | r#" | ||
733 | struct HasUnsafe; | ||
734 | |||
735 | impl HasUnsafe { | ||
736 | unsafe fn unsafe_fn(&self) { | ||
737 | let x = &5 as *const usize; | ||
738 | let y = *x; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | unsafe fn unsafe_fn() { | ||
743 | let x = &5 as *const usize; | ||
744 | let y = *x; | ||
745 | } | ||
746 | |||
747 | fn main() { | ||
748 | unsafe_fn(); | ||
749 | //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
750 | HasUnsafe.unsafe_fn(); | ||
751 | //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
752 | unsafe { | ||
753 | unsafe_fn(); | ||
754 | HasUnsafe.unsafe_fn(); | ||
755 | } | ||
756 | } | ||
757 | "#, | ||
758 | ); | ||
759 | } | ||
760 | |||
761 | #[test] | ||
762 | fn missing_unsafe_diagnostic_with_static_mut() { | ||
763 | check_diagnostics( | ||
764 | r#" | ||
765 | struct Ty { | ||
766 | a: u8, | ||
767 | } | ||
768 | |||
769 | static mut STATIC_MUT: Ty = Ty { a: 0 }; | ||
770 | |||
771 | fn main() { | ||
772 | let x = STATIC_MUT.a; | ||
773 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
774 | unsafe { | ||
775 | let x = STATIC_MUT.a; | ||
776 | } | ||
777 | } | ||
778 | "#, | ||
779 | ); | ||
780 | } | ||
781 | |||
782 | #[test] | ||
783 | fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { | ||
784 | check_diagnostics( | ||
785 | r#" | ||
786 | extern "rust-intrinsic" { | ||
787 | pub fn bitreverse(x: u32) -> u32; // Safe intrinsic | ||
788 | pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic | ||
789 | } | ||
790 | |||
791 | fn main() { | ||
792 | let _ = bitreverse(12); | ||
793 | let _ = floorf32(12.0); | ||
794 | //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
795 | } | ||
796 | "#, | ||
797 | ); | ||
798 | } | ||
799 | |||
800 | // Register the required standard library types to make the tests work | 718 | // Register the required standard library types to make the tests work |
801 | fn add_filter_map_with_find_next_boilerplate(body: &str) -> String { | 719 | fn add_filter_map_with_find_next_boilerplate(body: &str) -> String { |
802 | let prefix = r#" | 720 | let prefix = r#" |
diff --git a/crates/ide/src/diagnostics/missing_unsafe.rs b/crates/ide/src/diagnostics/missing_unsafe.rs new file mode 100644 index 000000000..5c47e8d0a --- /dev/null +++ b/crates/ide/src/diagnostics/missing_unsafe.rs | |||
@@ -0,0 +1,101 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | ||
2 | |||
3 | // Diagnostic: missing-unsafe | ||
4 | // | ||
5 | // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. | ||
6 | pub(super) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { | ||
7 | Diagnostic::new( | ||
8 | "missing-unsafe", | ||
9 | "this operation is unsafe and requires an unsafe function or block", | ||
10 | ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, | ||
11 | ) | ||
12 | } | ||
13 | |||
14 | #[cfg(test)] | ||
15 | mod tests { | ||
16 | use crate::diagnostics::tests::check_diagnostics; | ||
17 | |||
18 | #[test] | ||
19 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
20 | check_diagnostics( | ||
21 | r#" | ||
22 | fn main() { | ||
23 | let x = &5 as *const usize; | ||
24 | unsafe { let y = *x; } | ||
25 | let z = *x; | ||
26 | } //^^ this operation is unsafe and requires an unsafe function or block | ||
27 | "#, | ||
28 | ) | ||
29 | } | ||
30 | |||
31 | #[test] | ||
32 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
33 | check_diagnostics( | ||
34 | r#" | ||
35 | struct HasUnsafe; | ||
36 | |||
37 | impl HasUnsafe { | ||
38 | unsafe fn unsafe_fn(&self) { | ||
39 | let x = &5 as *const usize; | ||
40 | let y = *x; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | unsafe fn unsafe_fn() { | ||
45 | let x = &5 as *const usize; | ||
46 | let y = *x; | ||
47 | } | ||
48 | |||
49 | fn main() { | ||
50 | unsafe_fn(); | ||
51 | //^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | ||
52 | HasUnsafe.unsafe_fn(); | ||
53 | //^^^^^^^^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | ||
54 | unsafe { | ||
55 | unsafe_fn(); | ||
56 | HasUnsafe.unsafe_fn(); | ||
57 | } | ||
58 | } | ||
59 | "#, | ||
60 | ); | ||
61 | } | ||
62 | |||
63 | #[test] | ||
64 | fn missing_unsafe_diagnostic_with_static_mut() { | ||
65 | check_diagnostics( | ||
66 | r#" | ||
67 | struct Ty { | ||
68 | a: u8, | ||
69 | } | ||
70 | |||
71 | static mut STATIC_MUT: Ty = Ty { a: 0 }; | ||
72 | |||
73 | fn main() { | ||
74 | let x = STATIC_MUT.a; | ||
75 | //^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | ||
76 | unsafe { | ||
77 | let x = STATIC_MUT.a; | ||
78 | } | ||
79 | } | ||
80 | "#, | ||
81 | ); | ||
82 | } | ||
83 | |||
84 | #[test] | ||
85 | fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { | ||
86 | check_diagnostics( | ||
87 | r#" | ||
88 | extern "rust-intrinsic" { | ||
89 | pub fn bitreverse(x: u32) -> u32; // Safe intrinsic | ||
90 | pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic | ||
91 | } | ||
92 | |||
93 | fn main() { | ||
94 | let _ = bitreverse(12); | ||
95 | let _ = floorf32(12.0); | ||
96 | //^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | ||
97 | } | ||
98 | "#, | ||
99 | ); | ||
100 | } | ||
101 | } | ||