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.rs154
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;
+}
+
+ "#,
+ )
+ }
}