diff options
author | Aleksey Kladov <[email protected]> | 2021-06-13 18:00:27 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-06-13 18:01:01 +0100 |
commit | bccf77f26cd504de14f7d7d03f9f2a85d0fabb3d (patch) | |
tree | 2d38ea6fb04b05a44467bd9614253b8621848f20 /crates | |
parent | 886b66cd03cbe7cb13e248d7c7bbdeba66c7796a (diff) |
internal: refactor missing unsafe diagnostic
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir/src/diagnostics.rs | 22 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ide/src/diagnostics.rs | 86 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/missing_unsafe.rs | 101 |
4 files changed, 106 insertions, 107 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 47d17ba70..f7bf63215 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -36,6 +36,7 @@ diagnostics![ | |||
36 | InactiveCode, | 36 | InactiveCode, |
37 | MacroError, | 37 | MacroError, |
38 | MissingFields, | 38 | MissingFields, |
39 | MissingUnsafe, | ||
39 | NoSuchField, | 40 | NoSuchField, |
40 | UnimplementedBuiltinMacro, | 41 | UnimplementedBuiltinMacro, |
41 | UnresolvedExternCrate, | 42 | UnresolvedExternCrate, |
@@ -104,28 +105,9 @@ pub struct BreakOutsideOfLoop { | |||
104 | pub expr: InFile<AstPtr<ast::Expr>>, | 105 | pub expr: InFile<AstPtr<ast::Expr>>, |
105 | } | 106 | } |
106 | 107 | ||
107 | // Diagnostic: missing-unsafe | ||
108 | // | ||
109 | // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. | ||
110 | #[derive(Debug)] | 108 | #[derive(Debug)] |
111 | pub struct MissingUnsafe { | 109 | pub struct MissingUnsafe { |
112 | pub file: HirFileId, | 110 | pub expr: InFile<AstPtr<ast::Expr>>, |
113 | pub expr: AstPtr<ast::Expr>, | ||
114 | } | ||
115 | |||
116 | impl Diagnostic for MissingUnsafe { | ||
117 | fn code(&self) -> DiagnosticCode { | ||
118 | DiagnosticCode("missing-unsafe") | ||
119 | } | ||
120 | fn message(&self) -> String { | ||
121 | format!("This operation is unsafe and requires an unsafe function or block") | ||
122 | } | ||
123 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
124 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
125 | } | ||
126 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
127 | self | ||
128 | } | ||
129 | } | 111 | } |
130 | 112 | ||
131 | #[derive(Debug)] | 113 | #[derive(Debug)] |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 2f507b83b..16f862707 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -1090,9 +1090,7 @@ impl Function { | |||
1090 | 1090 | ||
1091 | for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) { | 1091 | for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) { |
1092 | match source_map.expr_syntax(expr) { | 1092 | match source_map.expr_syntax(expr) { |
1093 | Ok(in_file) => { | 1093 | Ok(expr) => acc.push(MissingUnsafe { expr }.into()), |
1094 | sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) | ||
1095 | } | ||
1096 | Err(SyntheticSyntax) => { | 1094 | Err(SyntheticSyntax) => { |
1097 | // FIXME: Here and eslwhere in this file, the `expr` was | 1095 | // FIXME: Here and eslwhere in this file, the `expr` was |
1098 | // desugared, report or assert that this doesn't happen. | 1096 | // desugared, report or assert that this doesn't happen. |
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 | } | ||