From 002f6ad6f1ca6aa59e1ebccc8478930101f8150f Mon Sep 17 00:00:00 2001 From: roife Date: Sun, 20 Oct 2024 19:48:15 +0800 Subject: [PATCH] fix: do not emit unsafe diagnositcs for safe statics in extern blocks --- crates/hir-def/src/data.rs | 4 +++ crates/hir-def/src/item_tree.rs | 3 ++ crates/hir-def/src/item_tree/lower.rs | 5 ++- crates/hir-def/src/item_tree/pretty.rs | 16 ++++++++- crates/hir-ty/src/diagnostics/unsafe_check.rs | 2 +- .../src/handlers/missing_unsafe.rs | 35 +++++++++++++++++++ 6 files changed, 62 insertions(+), 3 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index f2c49813fa..263fad51d7 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -571,6 +571,8 @@ pub struct StaticData { pub visibility: RawVisibility, pub mutable: bool, pub is_extern: bool, + pub has_safe_kw: bool, + pub has_unsafe_kw: bool, } impl StaticData { @@ -585,6 +587,8 @@ impl StaticData { visibility: item_tree[statik.visibility].clone(), mutable: statik.mutable, is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), + has_safe_kw: statik.has_safe_kw, + has_unsafe_kw: statik.has_unsafe_kw, }) } } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 4bee7eeb9e..7cb833fdce 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -823,7 +823,10 @@ pub struct Const { pub struct Static { pub name: Name, pub visibility: RawVisibilityId, + // TODO: use bitflags when we have more flags pub mutable: bool, + pub has_safe_kw: bool, + pub has_unsafe_kw: bool, pub type_ref: Interned, pub ast_id: FileAstId, } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 1d8d236d97..431a7f66f4 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -487,8 +487,11 @@ impl<'a> Ctx<'a> { let type_ref = self.lower_type_ref_opt(static_.ty()); let visibility = self.lower_visibility(static_); let mutable = static_.mut_token().is_some(); + let has_safe_kw = static_.safe_token().is_some(); + let has_unsafe_kw = static_.unsafe_token().is_some(); let ast_id = self.source_ast_id_map.ast_id(static_); - let res = Static { name, visibility, mutable, type_ref, ast_id }; + let res = + Static { name, visibility, mutable, type_ref, ast_id, has_safe_kw, has_unsafe_kw }; Some(id(self.data().statics.alloc(res))) } diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 5ab4718a36..9dce28b2e4 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -382,9 +382,23 @@ impl Printer<'_> { wln!(self, " = _;"); } ModItem::Static(it) => { - let Static { name, visibility, mutable, type_ref, ast_id } = &self.tree[it]; + let Static { + name, + visibility, + mutable, + type_ref, + ast_id, + has_safe_kw, + has_unsafe_kw, + } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); + if *has_safe_kw { + w!(self, "safe "); + } + if *has_unsafe_kw { + w!(self, "unsafe "); + } w!(self, "static "); if *mutable { w!(self, "mut "); diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index ff45c725c7..bcfc37c867 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -89,7 +89,7 @@ fn walk_unsafe( let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path); if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { let static_data = db.static_data(id); - if static_data.mutable || static_data.is_extern { + if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) { unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); } } diff --git a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index a53dd31286..cc0f4bfccc 100644 --- a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -595,4 +595,39 @@ unsafe fn foo(p: *mut i32) { "#, ) } + + #[test] + fn no_unsafe_diagnostic_with_safe_kw() { + check_diagnostics( + r#" +unsafe extern { + pub safe fn f(); + + pub unsafe fn g(); + + pub fn h(); + + pub safe static S1: i32; + + pub unsafe static S2: i32; + + pub static S3: i32; +} + +fn main() { + f(); + g(); + //^^^💡 error: this operation is unsafe and requires an unsafe function or block + h(); + //^^^💡 error: this operation 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 + let _ = S3; + //^^💡 error: this operation is unsafe and requires an unsafe function or block +} +"#, + ); + } }