From bccf77f26cd504de14f7d7d03f9f2a85d0fabb3d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 13 Jun 2021 20:00:27 +0300 Subject: internal: refactor missing unsafe diagnostic --- crates/hir/src/diagnostics.rs | 22 +----- crates/hir/src/lib.rs | 4 +- crates/ide/src/diagnostics.rs | 86 +---------------------- crates/ide/src/diagnostics/missing_unsafe.rs | 101 +++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 107 deletions(-) create mode 100644 crates/ide/src/diagnostics/missing_unsafe.rs 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![ InactiveCode, MacroError, MissingFields, + MissingUnsafe, NoSuchField, UnimplementedBuiltinMacro, UnresolvedExternCrate, @@ -104,28 +105,9 @@ pub struct BreakOutsideOfLoop { pub expr: InFile>, } -// Diagnostic: missing-unsafe -// -// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. #[derive(Debug)] pub struct MissingUnsafe { - pub file: HirFileId, - pub expr: AstPtr, -} - -impl Diagnostic for MissingUnsafe { - fn code(&self) -> DiagnosticCode { - DiagnosticCode("missing-unsafe") - } - fn message(&self) -> String { - format!("This operation is unsafe and requires an unsafe function or block") - } - fn display_source(&self) -> InFile { - InFile { file_id: self.file, value: self.expr.clone().into() } - } - fn as_any(&self) -> &(dyn Any + Send + 'static) { - self - } + pub expr: InFile>, } #[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 { for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) { match source_map.expr_syntax(expr) { - Ok(in_file) => { - sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) - } + Ok(expr) => acc.push(MissingUnsafe { expr }.into()), Err(SyntheticSyntax) => { // FIXME: Here and eslwhere in this file, the `expr` was // 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; mod inactive_code; mod macro_error; mod missing_fields; +mod missing_unsafe; mod no_such_field; mod unimplemented_builtin_macro; mod unresolved_extern_crate; @@ -222,6 +223,7 @@ pub(crate) fn diagnostics( AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d), AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), + AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), @@ -713,90 +715,6 @@ mod foo; ); } - #[test] - fn missing_unsafe_diagnostic_with_raw_ptr() { - check_diagnostics( - r#" -fn main() { - let x = &5 as *const usize; - unsafe { let y = *x; } - let z = *x; -} //^^ This operation is unsafe and requires an unsafe function or block -"#, - ) - } - - #[test] - fn missing_unsafe_diagnostic_with_unsafe_call() { - check_diagnostics( - r#" -struct HasUnsafe; - -impl HasUnsafe { - unsafe fn unsafe_fn(&self) { - let x = &5 as *const usize; - let y = *x; - } -} - -unsafe fn unsafe_fn() { - let x = &5 as *const usize; - let y = *x; -} - -fn main() { - unsafe_fn(); - //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block - HasUnsafe.unsafe_fn(); - //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block - unsafe { - unsafe_fn(); - HasUnsafe.unsafe_fn(); - } -} -"#, - ); - } - - #[test] - fn missing_unsafe_diagnostic_with_static_mut() { - check_diagnostics( - r#" -struct Ty { - a: u8, -} - -static mut STATIC_MUT: Ty = Ty { a: 0 }; - -fn main() { - let x = STATIC_MUT.a; - //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block - unsafe { - let x = STATIC_MUT.a; - } -} -"#, - ); - } - - #[test] - fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { - check_diagnostics( - r#" -extern "rust-intrinsic" { - pub fn bitreverse(x: u32) -> u32; // Safe intrinsic - pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic -} - -fn main() { - let _ = bitreverse(12); - let _ = floorf32(12.0); - //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block -} -"#, - ); - } - // Register the required standard library types to make the tests work fn add_filter_map_with_find_next_boilerplate(body: &str) -> String { 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 @@ +use crate::diagnostics::{Diagnostic, DiagnosticsContext}; + +// Diagnostic: missing-unsafe +// +// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. +pub(super) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { + Diagnostic::new( + "missing-unsafe", + "this operation is unsafe and requires an unsafe function or block", + ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, + ) +} + +#[cfg(test)] +mod tests { + use crate::diagnostics::tests::check_diagnostics; + + #[test] + fn missing_unsafe_diagnostic_with_raw_ptr() { + check_diagnostics( + r#" +fn main() { + let x = &5 as *const usize; + unsafe { let y = *x; } + let z = *x; +} //^^ this operation is unsafe and requires an unsafe function or block +"#, + ) + } + + #[test] + fn missing_unsafe_diagnostic_with_unsafe_call() { + check_diagnostics( + r#" +struct HasUnsafe; + +impl HasUnsafe { + unsafe fn unsafe_fn(&self) { + let x = &5 as *const usize; + let y = *x; + } +} + +unsafe fn unsafe_fn() { + let x = &5 as *const usize; + let y = *x; +} + +fn main() { + unsafe_fn(); + //^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block + HasUnsafe.unsafe_fn(); + //^^^^^^^^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block + unsafe { + unsafe_fn(); + HasUnsafe.unsafe_fn(); + } +} +"#, + ); + } + + #[test] + fn missing_unsafe_diagnostic_with_static_mut() { + check_diagnostics( + r#" +struct Ty { + a: u8, +} + +static mut STATIC_MUT: Ty = Ty { a: 0 }; + +fn main() { + let x = STATIC_MUT.a; + //^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block + unsafe { + let x = STATIC_MUT.a; + } +} +"#, + ); + } + + #[test] + fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { + check_diagnostics( + r#" +extern "rust-intrinsic" { + pub fn bitreverse(x: u32) -> u32; // Safe intrinsic + pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic +} + +fn main() { + let _ = bitreverse(12); + let _ = floorf32(12.0); + //^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block +} +"#, + ); + } +} -- cgit v1.2.3