Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-diagnostics/src/handlers/missing_unsafe.rs')
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/missing_unsafe.rs | 154 |
1 files changed, 134 insertions, 20 deletions
diff --git a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index a630d3c7c3..2bfdda3565 100644 --- a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -1,5 +1,5 @@ use hir::db::ExpandDatabase; -use hir::HirFileIdExt; +use hir::{HirFileIdExt, UnsafetyReason}; use ide_db::text_edit::TextEdit; use ide_db::{assists::Assist, source_change::SourceChange}; use syntax::{ast, SyntaxNode}; @@ -16,23 +16,35 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf } else { DiagnosticCode::RustcHardError("E0133") }; + let operation = display_unsafety_reason(d.reason); Diagnostic::new_with_syntax_node_ptr( ctx, code, - "this operation is unsafe and requires an unsafe function or block", - d.expr.map(|it| it.into()), + format!("{operation} is unsafe and requires an unsafe function or block"), + d.node.map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) } +fn display_unsafety_reason(reason: UnsafetyReason) -> &'static str { + match reason { + UnsafetyReason::UnionField => "access to union field", + UnsafetyReason::UnsafeFnCall => "call to unsafe function", + UnsafetyReason::InlineAsm => "use of inline assembly", + UnsafetyReason::RawPtrDeref => "dereference of raw pointer", + UnsafetyReason::MutableStatic => "use of mutable static", + UnsafetyReason::ExternStatic => "use of extern static", + } +} + fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option<Vec<Assist>> { // The fixit will not work correctly for macro expansions, so we don't offer it in that case. - if d.expr.file_id.is_macro() { + if d.node.file_id.is_macro() { return None; } - let root = ctx.sema.db.parse_or_expand(d.expr.file_id); - let node = d.expr.value.to_node(&root); + let root = ctx.sema.db.parse_or_expand(d.node.file_id); + let node = d.node.value.to_node(&root); let expr = node.syntax().ancestors().find_map(ast::Expr::cast)?; let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?; @@ -40,7 +52,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option<Vec<Ass let replacement = format!("unsafe {{ {} }}", node_to_add_unsafe_block.text()); let edit = TextEdit::replace(node_to_add_unsafe_block.text_range(), replacement); let source_change = - SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit); + SourceChange::from_text_edit(d.node.file_id.original_file(ctx.sema.db), edit); Some(vec![fix("add_unsafe", "Add unsafe block", source_change, expr.syntax().text_range())]) } @@ -110,7 +122,7 @@ fn main() { let x = &5_usize as *const usize; unsafe { let _y = *x; } let _z = *x; -} //^^💡 error: this operation is unsafe and requires an unsafe function or block +} //^^💡 error: dereference of raw pointer is unsafe and requires an unsafe function or block "#, ) } @@ -136,9 +148,9 @@ unsafe fn unsafe_fn() { fn main() { unsafe_fn(); - //^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block HasUnsafe.unsafe_fn(); - //^^^^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block unsafe { unsafe_fn(); HasUnsafe.unsafe_fn(); @@ -162,7 +174,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 }; fn main() { let _x = STATIC_MUT.a; - //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^💡 error: use of mutable static is unsafe and requires an unsafe function or block unsafe { let _x = STATIC_MUT.a; } @@ -184,9 +196,9 @@ extern "C" { fn main() { let _x = EXTERN; - //^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^💡 error: use of extern static is unsafe and requires an unsafe function or block let _x = EXTERN_MUT; - //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^💡 error: use of mutable static is unsafe and requires an unsafe function or block unsafe { let _x = EXTERN; let _x = EXTERN_MUT; @@ -234,7 +246,7 @@ extern "rust-intrinsic" { fn main() { let _ = bitreverse(12); let _ = floorf32(12.0); - //^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block } "#, ); @@ -567,7 +579,7 @@ unsafe fn not_safe() -> u8 { fn main() { ed2021::safe(); ed2024::not_safe(); - //^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block } "#, ) @@ -591,7 +603,7 @@ unsafe fn foo(p: *mut i32) { #![warn(unsafe_op_in_unsafe_fn)] unsafe fn foo(p: *mut i32) { *p = 123; - //^^💡 warn: this operation is unsafe and requires an unsafe function or block + //^^💡 warn: dereference of raw pointer is unsafe and requires an unsafe function or block } "#, ) @@ -618,17 +630,119 @@ unsafe extern { fn main() { f(); g(); - //^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block h(); - //^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block let _ = S1; let _ = S2; - //^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^💡 error: use of extern static is unsafe and requires an unsafe function or block let _ = S3; - //^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^💡 error: use of extern static is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn no_unsafe_diagnostic_when_destructuring_union_with_wildcard() { + check_diagnostics( + r#" +union Union { field: i32 } +fn foo(v: &Union) { + let Union { field: _ } = v; + let Union { field: _ | _ } = v; + Union { field: _ } = *v; +} +"#, + ); + } + + #[test] + fn union_destructuring() { + check_diagnostics( + r#" +union Union { field: u8 } +fn foo(v @ Union { field: _field }: &Union) { + // ^^^^^^ error: access to union field is unsafe and requires an unsafe function or block + let Union { mut field } = v; + // ^^^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + let Union { field: 0..=255 } = v; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + let Union { field: 0 + // ^💡 error: access to union field is unsafe and requires an unsafe function or block + | 1..=255 } = v; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + Union { field } = *v; + // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + match v { + Union { field: _field } => {} + // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + } + if let Union { field: _field } = v {} + // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + (|&Union { field }| { _ = field; })(v); + // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn union_field_access() { + check_diagnostics( + r#" +union Union { field: u8 } +fn foo(v: &Union) { + v.field; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block } "#, ); } + + #[test] + fn inline_asm() { + check_diagnostics( + r#" +//- minicore: asm +fn foo() { + core::arch::asm!(""); + // ^^^^ error: use of inline assembly is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn unsafe_op_in_unsafe_fn_dismissed_in_signature() { + check_diagnostics( + r#" +#![warn(unsafe_op_in_unsafe_fn)] +union Union { field: u32 } +unsafe fn foo(Union { field: _field }: Union) {} + "#, + ) + } + + #[test] + fn union_assignment_allowed() { + check_diagnostics( + r#" +union Union { field: u32 } +fn foo(mut v: Union) { + v.field = 123; + (v.field,) = (123,); + *&mut v.field = 123; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block +} +struct Struct { field: u32 } +union Union2 { field: Struct } +fn bar(mut v: Union2) { + v.field.field = 123; +} + + "#, + ) + } } |