about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAli Bektas <bektasali@protonmail.com>2025-03-17 22:37:21 +0100
committerAli Bektas <bektasali@protonmail.com>2025-03-17 22:37:21 +0100
commitd88a6159eaed3f6ef33277bbd817a48b9a11b51c (patch)
treea2adf758956021199af5f98638982cb8ff2ba5fc
parent1919a66f9377d49c356a49953bc0d2e6e43c8b57 (diff)
downloadrust-d88a6159eaed3f6ef33277bbd817a48b9a11b51c.tar.gz
rust-d88a6159eaed3f6ef33277bbd817a48b9a11b51c.zip
Test unsafeness is respected when manual impling derives
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs50
1 files changed, 45 insertions, 5 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index 8ff9fe09b56..e0693a7d5b6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -131,7 +131,7 @@ fn add_assist(
         target,
         |builder| {
             let insert_after = ted::Position::after(builder.make_mut(adt.clone()).syntax());
-
+            let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
             let impl_def_with_items =
                 impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
             update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
@@ -141,6 +141,12 @@ fn add_assist(
             match (ctx.config.snippet_cap, impl_def_with_items) {
                 (None, None) => {
                     let impl_def = generate_trait_impl(adt, trait_path);
+                    if impl_is_unsafe {
+                        ted::insert(
+                            Position::first_child_of(impl_def.syntax()),
+                            make::token(T![unsafe]),
+                        );
+                    }
 
                     ted::insert_all(
                         insert_after,
@@ -148,6 +154,12 @@ fn add_assist(
                     );
                 }
                 (None, Some((impl_def, _))) => {
+                    if impl_is_unsafe {
+                        ted::insert(
+                            Position::first_child_of(impl_def.syntax()),
+                            make::token(T![unsafe]),
+                        );
+                    }
                     ted::insert_all(
                         insert_after,
                         vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
@@ -156,6 +168,13 @@ fn add_assist(
                 (Some(cap), None) => {
                     let impl_def = generate_trait_impl(adt, trait_path);
 
+                    if impl_is_unsafe {
+                        ted::insert(
+                            Position::first_child_of(impl_def.syntax()),
+                            make::token(T![unsafe]),
+                        );
+                    }
+
                     if let Some(l_curly) =
                         impl_def.assoc_item_list().and_then(|it| it.l_curly_token())
                     {
@@ -169,6 +188,14 @@ fn add_assist(
                 }
                 (Some(cap), Some((impl_def, first_assoc_item))) => {
                     let mut added_snippet = false;
+
+                    if impl_is_unsafe {
+                        ted::insert(
+                            Position::first_child_of(impl_def.syntax()),
+                            make::token(T![unsafe]),
+                        );
+                    }
+
                     if let ast::AssocItem::Fn(ref func) = first_assoc_item {
                         if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
                         {
@@ -223,10 +250,6 @@ fn impl_def_from_trait(
     let first_assoc_item =
         add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, &target_scope);
 
-    if trait_.is_unsafe(sema.db) {
-        ted::insert(Position::first_child_of(impl_def.syntax()), make::token(T![unsafe]));
-    }
-
     // Generate a default `impl` function body for the derived trait.
     if let ast::AssocItem::Fn(ref func) = first_assoc_item {
         let _ = gen_trait_fn_body(func, trait_path, adt, None);
@@ -1409,4 +1432,21 @@ impl core::fmt::Debug for Foo {
 "#,
         )
     }
+
+    #[test]
+    fn unsafeness_of_a_trait_observed() {
+        check_assist(
+            replace_derive_with_manual_impl,
+            r#"
+//- minicore: send, derive
+#[derive(Sen$0d)]
+pub struct Foo;
+"#,
+            r#"
+pub struct Foo;
+
+unsafe impl Send for Foo {$0}
+"#,
+        )
+    }
 }