aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/diagnostics.rs22
-rw-r--r--crates/hir/src/lib.rs4
-rw-r--r--crates/ide/src/diagnostics.rs86
-rw-r--r--crates/ide/src/diagnostics/missing_unsafe.rs101
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)]
111pub struct MissingUnsafe { 109pub struct MissingUnsafe {
112 pub file: HirFileId, 110 pub expr: InFile<AstPtr<ast::Expr>>,
113 pub expr: AstPtr<ast::Expr>,
114}
115
116impl 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;
8mod inactive_code; 8mod inactive_code;
9mod macro_error; 9mod macro_error;
10mod missing_fields; 10mod missing_fields;
11mod missing_unsafe;
11mod no_such_field; 12mod no_such_field;
12mod unimplemented_builtin_macro; 13mod unimplemented_builtin_macro;
13mod unresolved_extern_crate; 14mod 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#"
720fn 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#"
733struct HasUnsafe;
734
735impl HasUnsafe {
736 unsafe fn unsafe_fn(&self) {
737 let x = &5 as *const usize;
738 let y = *x;
739 }
740}
741
742unsafe fn unsafe_fn() {
743 let x = &5 as *const usize;
744 let y = *x;
745}
746
747fn 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#"
765struct Ty {
766 a: u8,
767}
768
769static mut STATIC_MUT: Ty = Ty { a: 0 };
770
771fn 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#"
786extern "rust-intrinsic" {
787 pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
788 pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
789}
790
791fn 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 @@
1use 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.
6pub(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)]
15mod tests {
16 use crate::diagnostics::tests::check_diagnostics;
17
18 #[test]
19 fn missing_unsafe_diagnostic_with_raw_ptr() {
20 check_diagnostics(
21 r#"
22fn 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#"
35struct HasUnsafe;
36
37impl HasUnsafe {
38 unsafe fn unsafe_fn(&self) {
39 let x = &5 as *const usize;
40 let y = *x;
41 }
42}
43
44unsafe fn unsafe_fn() {
45 let x = &5 as *const usize;
46 let y = *x;
47}
48
49fn 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#"
67struct Ty {
68 a: u8,
69}
70
71static mut STATIC_MUT: Ty = Ty { a: 0 };
72
73fn 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#"
88extern "rust-intrinsic" {
89 pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
90 pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
91}
92
93fn 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}