remvoe add_attr edit_in_place.rs because it use ted.
diff --git a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
index f73b8c4..c208c8b 100644
--- a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
+++ b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
@@ -13,12 +13,7 @@
 use itertools::Itertools;
 use syntax::{
     AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
-    ast::{
-        self, HasName,
-        edit::IndentLevel,
-        edit_in_place::{AttrsOwnerEdit, Indent},
-        make,
-    },
+    ast::{self, HasName, edit::IndentLevel, edit_in_place::Indent, make},
 };
 
 use crate::{
@@ -506,18 +501,6 @@
 }
 
 fn make_bool_enum(make_pub: bool) -> ast::Enum {
-    let enum_def = make::enum_(
-        if make_pub { Some(make::visibility_pub()) } else { None },
-        make::name("Bool"),
-        None,
-        None,
-        make::variant_list(vec![
-            make::variant(None, make::name("True"), None, None),
-            make::variant(None, make::name("False"), None, None),
-        ]),
-    )
-    .clone_for_update();
-
     let derive_eq = make::attr_outer(make::meta_token_tree(
         make::ext::ident_path("derive"),
         make::token_tree(
@@ -529,11 +512,19 @@
                 NodeOrToken::Token(make::tokens::ident("Eq")),
             ],
         ),
-    ))
-    .clone_for_update();
-    enum_def.add_attr(derive_eq);
-
-    enum_def
+    ));
+    make::enum_(
+        [derive_eq],
+        if make_pub { Some(make::visibility_pub()) } else { None },
+        make::name("Bool"),
+        None,
+        None,
+        make::variant_list(vec![
+            make::variant(None, make::name("True"), None, None),
+            make::variant(None, make::name("False"), None, None),
+        ]),
+    )
+    .clone_for_update()
 }
 
 #[cfg(test)]
diff --git a/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index 916bb67..5f526ec 100644
--- a/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -236,6 +236,7 @@
             };
             let mut fn_ = make::fn_(
                 None,
+                None,
                 closure_name_or_default.clone(),
                 closure_type_params,
                 closure_where_clause,
diff --git a/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
index f1cc3d9..7d8b763 100644
--- a/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
+++ b/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
@@ -96,6 +96,7 @@
             }
 
             let error_type = ast::AssocItem::TypeAlias(make::ty_alias(
+                None,
                 "Error",
                 None,
                 None,
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index 890b8dd..d88e331 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -1642,6 +1642,7 @@
 
     make::fn_(
         None,
+        None,
         fun_name,
         generic_params,
         where_clause,
diff --git a/crates/ide-assists/src/handlers/extract_module.rs b/crates/ide-assists/src/handlers/extract_module.rs
index c6a6b97..da91d0a 100644
--- a/crates/ide-assists/src/handlers/extract_module.rs
+++ b/crates/ide-assists/src/handlers/extract_module.rs
@@ -586,6 +586,7 @@
             if (def_out_sel || !is_item) && use_stmt_not_in_sel {
                 let use_ = make::use_(
                     None,
+                    None,
                     make::use_tree(make::join_paths(use_tree_paths), None, None, false),
                 );
                 self.use_items.insert(0, ast::Item::from(use_));
@@ -600,6 +601,7 @@
         let node_path = make::ext::ident_path(&node_syntax.to_string());
         let use_ = make::use_(
             None,
+            None,
             make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false),
         );
 
diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs
index 79f2238..7f93506 100644
--- a/crates/ide-assists/src/handlers/extract_type_alias.rs
+++ b/crates/ide-assists/src/handlers/extract_type_alias.rs
@@ -69,8 +69,9 @@
             edit.replace(ty.syntax(), new_ty.syntax());
 
             // Insert new alias
-            let ty_alias = make::ty_alias("Type", generic_params, None, None, Some((ty, None)))
-                .clone_for_update();
+            let ty_alias =
+                make::ty_alias(None, "Type", generic_params, None, None, Some((ty, None)))
+                    .clone_for_update();
 
             if let Some(cap) = ctx.config.snippet_cap
                 && let Some(name) = ty_alias.name()
diff --git a/crates/ide-assists/src/handlers/extract_variable.rs b/crates/ide-assists/src/handlers/extract_variable.rs
index c9c1969..bd88e8b 100644
--- a/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/crates/ide-assists/src/handlers/extract_variable.rs
@@ -200,7 +200,7 @@
                     }
                     ExtractionKind::Constant => {
                         let ast_ty = make.ty(&ty_string);
-                        ast::Item::Const(make.item_const(None, pat_name, ast_ty, initializer))
+                        ast::Item::Const(make.item_const(None, None, pat_name, ast_ty, initializer))
                             .into()
                     }
                     ExtractionKind::Static => {
diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index 2c81e28..d8a2e03 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -155,6 +155,7 @@
                 let ret_type = method_source.ret_type();
 
                 let f = make::fn_(
+                    None,
                     vis,
                     fn_name,
                     type_params,
@@ -195,6 +196,7 @@
                         let assoc_item_list = make::assoc_item_list(Some(vec![item]));
 
                         let impl_def = make::impl_(
+                            None,
                             ty_params,
                             ty_args,
                             make::ty_path(make::ext::ident_path(name)),
diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index e96250f..e87dde5 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -20,7 +20,6 @@
         HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path,
         WherePred,
         edit::{self, AstNodeEdit},
-        edit_in_place::AttrsOwnerEdit,
         make,
     },
     ted::{self, Position},
@@ -266,6 +265,7 @@
             let bound_params = bound_def.generic_param_list();
 
             let delegate = make::impl_trait(
+                None,
                 delegee.is_unsafe(db),
                 bound_params.clone(),
                 bound_params.map(|params| params.to_generic_args()),
@@ -379,6 +379,7 @@
             let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?;
             // 3) Generate delegate trait impl
             let delegate = make::impl_trait(
+                None,
                 trait_.is_unsafe(db),
                 trait_gen_params,
                 trait_gen_args,
@@ -652,8 +653,7 @@
     qual_path_ty: ast::Path,
     base_name: &str,
 ) -> Option<ast::AssocItem> {
-    let attrs = item.attrs();
-    let assoc = match item {
+    match item {
         AssocItem::Const(c) => const_assoc_item(c, qual_path_ty),
         AssocItem::Fn(f) => func_assoc_item(f, qual_path_ty, base_name),
         AssocItem::MacroCall(_) => {
@@ -662,18 +662,7 @@
             None
         }
         AssocItem::TypeAlias(ta) => ty_assoc_item(ta, qual_path_ty),
-    };
-    if let Some(assoc) = &assoc {
-        attrs.for_each(|attr| {
-            assoc.add_attr(attr.clone());
-            // fix indentations
-            if let Some(tok) = attr.syntax().next_sibling_or_token() {
-                let pos = Position::after(tok);
-                ted::insert(pos, make::tokens::whitespace("    "));
-            }
-        })
     }
-    assoc
 }
 
 fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option<AssocItem> {
@@ -687,6 +676,7 @@
     // make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap());
     let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
     let inner = make::item_const(
+        item.attrs(),
         item.visibility(),
         item.name()?,
         item.ty()?,
@@ -755,6 +745,7 @@
 
     let body = make::block_expr(vec![], Some(call.into())).clone_for_update();
     let func = make::fn_(
+        item.attrs(),
         item.visibility(),
         item.name()?,
         item.generic_param_list(),
@@ -779,13 +770,14 @@
     let ident = item.name()?.to_string();
 
     let alias = make::ty_alias(
+        item.attrs(),
         ident.as_str(),
         item.generic_param_list(),
         None,
         item.where_clause(),
         Some((ty, None)),
     )
-    .clone_for_update();
+    .indent(edit::IndentLevel(1));
 
     Some(AssocItem::TypeAlias(alias))
 }
@@ -1814,6 +1806,63 @@
     }
 
     #[test]
+    fn test_ty_alias_attrs() {
+        check_assist(
+            generate_delegate_trait,
+            r#"
+struct A;
+
+trait T {
+    #[cfg(test)]
+    type t;
+    #[cfg(not(test))]
+    type t;
+}
+
+impl T for A {
+    #[cfg(test)]
+    type t = u32;
+    #[cfg(not(test))]
+    type t = bool;
+}
+
+struct B {
+    a$0: A,
+}
+"#,
+            r#"
+struct A;
+
+trait T {
+    #[cfg(test)]
+    type t;
+    #[cfg(not(test))]
+    type t;
+}
+
+impl T for A {
+    #[cfg(test)]
+    type t = u32;
+    #[cfg(not(test))]
+    type t = bool;
+}
+
+struct B {
+    a: A,
+}
+
+impl T for B {
+    #[cfg(test)]
+    type t = <A as T>::t;
+
+    #[cfg(not(test))]
+    type t = <A as T>::t;
+}
+"#,
+        );
+    }
+
+    #[test]
     fn assoc_items_attributes_mutably_cloned() {
         check_assist(
             generate_delegate_trait,
diff --git a/crates/ide-assists/src/handlers/generate_derive.rs b/crates/ide-assists/src/handlers/generate_derive.rs
index 73a69c8..06fef4a 100644
--- a/crates/ide-assists/src/handlers/generate_derive.rs
+++ b/crates/ide-assists/src/handlers/generate_derive.rs
@@ -1,6 +1,8 @@
 use syntax::{
+    SyntaxKind::{ATTR, COMMENT, WHITESPACE},
     T,
-    ast::{self, AstNode, HasAttrs, edit_in_place::AttrsOwnerEdit, make},
+    ast::{self, AstNode, HasAttrs, edit::IndentLevel, make},
+    syntax_editor::{Element, Position},
 };
 
 use crate::{AssistContext, AssistId, Assists};
@@ -48,8 +50,20 @@
                 ))
                 .clone_for_update();
 
-                let nominal = edit.make_mut(nominal);
-                nominal.add_attr(derive.clone());
+                let mut editor = edit.make_editor(nominal.syntax());
+                let indent = IndentLevel::from_node(nominal.syntax());
+                let after_attrs_and_comments = nominal
+                    .syntax()
+                    .children_with_tokens()
+                    .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
+                    .map_or(Position::first_child_of(nominal.syntax()), Position::before);
+                editor.insert_all(
+                    after_attrs_and_comments,
+                    vec![
+                        derive.syntax().syntax_element(),
+                        make::tokens::whitespace(&format!("\n{indent}")).syntax_element(),
+                    ],
+                );
 
                 let delimiter = derive
                     .meta()
@@ -58,8 +72,9 @@
                     .expect("failed to get token tree out of Meta")
                     .r_paren_token()
                     .expect("make::attr_outer was expected to have a R_PAREN");
-
-                edit.add_tabstop_before_token(cap, delimiter);
+                let tabstop_before = edit.make_tabstop_before(cap);
+                editor.add_annotation(delimiter, tabstop_before);
+                edit.add_file_edits(ctx.vfs_file_id(), editor);
             }
             Some(_) => {
                 // Just move the cursor.
diff --git a/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
index 3c327a6..0b7eca2 100644
--- a/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
+++ b/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
@@ -94,6 +94,7 @@
 
                 // Insert new alias
                 let ty_alias = make::ty_alias(
+                    None,
                     &alias_name,
                     generic_params,
                     None,
diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs
index 613b32f..efdb20c 100644
--- a/crates/ide-assists/src/handlers/generate_function.rs
+++ b/crates/ide-assists/src/handlers/generate_function.rs
@@ -189,7 +189,7 @@
             )));
 
             // FIXME: adt may have generic params.
-            let impl_ = make::impl_(None, None, name, None, None).clone_for_update();
+            let impl_ = make::impl_(None, None, None, name, None, None).clone_for_update();
 
             func.indent(IndentLevel(1));
             impl_.get_or_create_assoc_item_list().add_item(func.into());
@@ -365,6 +365,7 @@
             Visibility::Pub => Some(make::visibility_pub()),
         };
         let fn_def = make::fn_(
+            None,
             visibility,
             self.fn_name,
             self.generic_param_list,
diff --git a/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index 807b919..e42d0ed 100644
--- a/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -263,6 +263,7 @@
     let body = make::block_expr([], Some(body));
 
     make::fn_(
+        None,
         strukt.visibility(),
         fn_name,
         None,
@@ -299,6 +300,7 @@
 
     // Make the setter fn
     make::fn_(
+        None,
         strukt.visibility(),
         fn_name,
         None,
diff --git a/crates/ide-assists/src/handlers/generate_impl.rs b/crates/ide-assists/src/handlers/generate_impl.rs
index b38ee6f..77eb8ef 100644
--- a/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/crates/ide-assists/src/handlers/generate_impl.rs
@@ -174,6 +174,7 @@
 
             let make_impl_ = |body| {
                 make::impl_trait(
+                    None,
                     trait_.unsafe_token().is_some(),
                     None,
                     trait_gen_args.clone(),
diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs
index 351f134..ac4a54a 100644
--- a/crates/ide-assists/src/handlers/generate_new.rs
+++ b/crates/ide-assists/src/handlers/generate_new.rs
@@ -134,6 +134,7 @@
         let ret_type = make::ret_type(make::ty_path(make::ext::ident_path("Self")));
 
         let fn_ = make::fn_(
+            None,
             strukt.visibility(),
             make::name("new"),
             None,
diff --git a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
index 4e95ceb..6076d5c 100644
--- a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
+++ b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
@@ -6,13 +6,12 @@
 };
 use syntax::{
     TokenText,
-    ast::{self, AstNode, HasGenericParams, HasName, edit, edit_in_place::Indent},
+    ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit, edit_in_place::Indent},
 };
 
 use crate::{
     AssistId,
     assist_context::{AssistContext, Assists},
-    utils::add_cfg_attrs_to,
 };
 
 // Assist: generate_single_field_struct_from
@@ -90,6 +89,7 @@
 
             let fn_ = make::fn_(
                 None,
+                None,
                 make::name("from"),
                 None,
                 None,
@@ -110,8 +110,12 @@
             .clone_for_update();
 
             fn_.indent(1.into());
+            let cfg_attrs = strukt
+                .attrs()
+                .filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
 
             let impl_ = make::impl_trait(
+                cfg_attrs,
                 false,
                 None,
                 trait_gen_args,
@@ -128,8 +132,6 @@
 
             impl_.get_or_create_assoc_item_list().add_item(fn_.into());
 
-            add_cfg_attrs_to(&strukt, &impl_);
-
             impl_.reindent_to(indent);
 
             builder.insert(strukt.syntax().text_range().end(), format!("\n\n{indent}{impl_}"));
diff --git a/crates/ide-assists/src/handlers/promote_local_to_const.rs b/crates/ide-assists/src/handlers/promote_local_to_const.rs
index 603be4d..547d368 100644
--- a/crates/ide-assists/src/handlers/promote_local_to_const.rs
+++ b/crates/ide-assists/src/handlers/promote_local_to_const.rs
@@ -88,7 +88,7 @@
                 }
             }
 
-            let item = make.item_const(None, make.name(&name), make.ty(&ty), initializer);
+            let item = make.item_const(None, None, make.name(&name), make.ty(&ty), initializer);
 
             if let Some((cap, name)) = ctx.config.snippet_cap.zip(item.name()) {
                 let tabstop = edit.make_tabstop_before(cap);
diff --git a/crates/ide-assists/src/handlers/unmerge_imports.rs b/crates/ide-assists/src/handlers/unmerge_imports.rs
index c066f41..accb5c2 100644
--- a/crates/ide-assists/src/handlers/unmerge_imports.rs
+++ b/crates/ide-assists/src/handlers/unmerge_imports.rs
@@ -1,9 +1,6 @@
 use syntax::{
     AstNode, SyntaxKind,
-    ast::{
-        self, HasAttrs, HasVisibility, edit::IndentLevel, edit_in_place::AttrsOwnerEdit, make,
-        syntax_factory::SyntaxFactory,
-    },
+    ast::{self, HasAttrs, HasVisibility, edit::IndentLevel, make, syntax_factory::SyntaxFactory},
     syntax_editor::{Element, Position, Removable},
 };
 
@@ -46,13 +43,10 @@
     acc.add(AssistId::refactor_rewrite("unmerge_imports"), label, target, |builder| {
         let make = SyntaxFactory::with_mappings();
         let new_use = make.use_(
+            use_.attrs(),
             use_.visibility(),
             make.use_tree(path, tree.use_tree_list(), tree.rename(), tree.star_token().is_some()),
         );
-        // Add any attributes that are present on the use tree
-        use_.attrs().for_each(|attr| {
-            new_use.add_attr(attr.clone_for_update());
-        });
 
         let mut editor = builder.make_editor(use_.syntax());
         // Remove the use tree from the current use item
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 91aac9c..20e0302 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -736,8 +736,11 @@
         generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update());
     let ty = make::ty_path(make::ext::ident_path(&adt.name().unwrap().text()));
 
-    let impl_ = match trait_ {
+    let cfg_attrs =
+        adt.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
+    match trait_ {
         Some(trait_) => make::impl_trait(
+            cfg_attrs,
             is_unsafe,
             None,
             None,
@@ -750,26 +753,9 @@
             adt.where_clause(),
             body,
         ),
-        None => make::impl_(generic_params, generic_args, ty, adt.where_clause(), body),
+        None => make::impl_(cfg_attrs, generic_params, generic_args, ty, adt.where_clause(), body),
     }
-    .clone_for_update();
-
-    // Copy any cfg attrs from the original adt
-    add_cfg_attrs_to(adt, &impl_);
-
-    impl_
-}
-
-pub(crate) fn add_cfg_attrs_to<T, U>(from: &T, to: &U)
-where
-    T: HasAttrs,
-    U: AttrsOwnerEdit,
-{
-    let cfg_attrs =
-        from.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
-    for attr in cfg_attrs {
-        to.add_attr(attr.clone_for_update());
-    }
+    .clone_for_update()
 }
 
 pub(crate) fn add_method_to_adt(
diff --git a/crates/ide-db/src/imports/insert_use.rs b/crates/ide-db/src/imports/insert_use.rs
index 08cd8f2..b174adf 100644
--- a/crates/ide-db/src/imports/insert_use.rs
+++ b/crates/ide-db/src/imports/insert_use.rs
@@ -194,7 +194,7 @@
         use_tree = use_tree.clone_for_update();
         use_tree.wrap_in_tree_list();
     }
-    let use_item = make::use_(None, use_tree).clone_for_update();
+    let use_item = make::use_(None, None, use_tree).clone_for_update();
     for attr in
         scope.required_cfgs.iter().map(|attr| attr.syntax().clone_subtree().clone_for_update())
     {
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index b50ce64..160f000 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -273,28 +273,6 @@
             }
         }
     }
-
-    fn add_attr(&self, attr: ast::Attr) {
-        add_attr(self.syntax(), attr);
-
-        fn add_attr(node: &SyntaxNode, attr: ast::Attr) {
-            let indent = IndentLevel::from_node(node);
-            attr.reindent_to(indent);
-
-            let after_attrs_and_comments = node
-                .children_with_tokens()
-                .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
-                .map_or(Position::first_child_of(node), Position::before);
-
-            ted::insert_all(
-                after_attrs_and_comments,
-                vec![
-                    attr.syntax().clone().into(),
-                    make::tokens::whitespace(&format!("\n{indent}")).into(),
-                ],
-            )
-        }
-    }
 }
 
 impl<T: ast::HasAttrs> AttrsOwnerEdit for T {}
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index daeb79c..c5ca609 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -190,6 +190,7 @@
 }
 
 pub fn ty_alias(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     ident: &str,
     generic_param_list: Option<ast::GenericParamList>,
     type_param_bounds: Option<ast::TypeParam>,
@@ -200,6 +201,7 @@
     let assignment_where = assignment_where.flatten();
     quote! {
         TypeAlias {
+            #(#attrs "\n")*
             [type] " "
                 Name { [IDENT ident] }
                 #generic_param_list
@@ -277,12 +279,16 @@
 }
 
 pub fn impl_(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     generic_params: Option<ast::GenericParamList>,
     generic_args: Option<ast::GenericArgList>,
     path_type: ast::Type,
     where_clause: Option<ast::WhereClause>,
     body: Option<ast::AssocItemList>,
 ) -> ast::Impl {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
+
     let gen_args = generic_args.map_or_else(String::new, |it| it.to_string());
 
     let gen_params = generic_params.map_or_else(String::new, |it| it.to_string());
@@ -295,10 +301,11 @@
     };
 
     let body = body.map_or_else(|| format!("{{{body_newline}}}"), |it| it.to_string());
-    ast_from_text(&format!("impl{gen_params} {path_type}{gen_args}{where_clause}{body}"))
+    ast_from_text(&format!("{attrs}impl{gen_params} {path_type}{gen_args}{where_clause}{body}"))
 }
 
 pub fn impl_trait(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     is_unsafe: bool,
     trait_gen_params: Option<ast::GenericParamList>,
     trait_gen_args: Option<ast::GenericArgList>,
@@ -311,6 +318,8 @@
     ty_where_clause: Option<ast::WhereClause>,
     body: Option<ast::AssocItemList>,
 ) -> ast::Impl {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let is_unsafe = if is_unsafe { "unsafe " } else { "" };
 
     let trait_gen_args = trait_gen_args.map(|args| args.to_string()).unwrap_or_default();
@@ -334,7 +343,7 @@
     let body = body.map_or_else(|| format!("{{{body_newline}}}"), |it| it.to_string());
 
     ast_from_text(&format!(
-        "{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{body}"
+        "{attrs}{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{body}"
     ))
 }
 
@@ -452,12 +461,18 @@
     ast_from_text(&format!("use {{{use_trees}}};"))
 }
 
-pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use {
+pub fn use_(
+    attrs: impl IntoIterator<Item = ast::Attr>,
+    visibility: Option<ast::Visibility>,
+    use_tree: ast::UseTree,
+) -> ast::Use {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let visibility = match visibility {
         None => String::new(),
         Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("{visibility}use {use_tree};"))
+    ast_from_text(&format!("{attrs}{visibility}use {use_tree};"))
 }
 
 pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr {
@@ -946,16 +961,19 @@
 }
 
 pub fn item_const(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     visibility: Option<ast::Visibility>,
     name: ast::Name,
     ty: ast::Type,
     expr: ast::Expr,
 ) -> ast::Const {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let visibility = match visibility {
         None => String::new(),
         Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("{visibility}const {name}: {ty} = {expr};"))
+    ast_from_text(&format!("{attrs}{visibility}const {name}: {ty} = {expr};"))
 }
 
 pub fn item_static(
@@ -1162,6 +1180,7 @@
 }
 
 pub fn fn_(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     visibility: Option<ast::Visibility>,
     fn_name: ast::Name,
     type_params: Option<ast::GenericParamList>,
@@ -1174,6 +1193,8 @@
     is_unsafe: bool,
     is_gen: bool,
 ) -> ast::Fn {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let type_params = match type_params {
         Some(type_params) => format!("{type_params}"),
         None => "".into(),
@@ -1197,7 +1218,7 @@
     let gen_literal = if is_gen { "gen " } else { "" };
 
     ast_from_text(&format!(
-        "{visibility}{const_literal}{async_literal}{gen_literal}{unsafe_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}",
+        "{attrs}{visibility}{const_literal}{async_literal}{gen_literal}{unsafe_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}",
     ))
 }
 pub fn struct_(
@@ -1217,12 +1238,15 @@
 }
 
 pub fn enum_(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     visibility: Option<ast::Visibility>,
     enum_name: ast::Name,
     generic_param_list: Option<ast::GenericParamList>,
     where_clause: Option<ast::WhereClause>,
     variant_list: ast::VariantList,
 ) -> ast::Enum {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let visibility = match visibility {
         None => String::new(),
         Some(it) => format!("{it} "),
@@ -1232,7 +1256,7 @@
     let where_clause = where_clause.map(|it| format!(" {it}")).unwrap_or_default();
 
     ast_from_text(&format!(
-        "{visibility}enum {enum_name}{generic_params}{where_clause} {variant_list}"
+        "{attrs}{visibility}enum {enum_name}{generic_params}{where_clause} {variant_list}"
     ))
 }
 
diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs
index 738a26f..8bf27f9 100644
--- a/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -2,8 +2,8 @@
 use crate::{
     AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken,
     ast::{
-        self, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, HasTypeBounds,
-        HasVisibility, RangeItem, make,
+        self, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasName,
+        HasTypeBounds, HasVisibility, RangeItem, make,
     },
     syntax_editor::SyntaxMappingBuilder,
 };
@@ -107,8 +107,13 @@
         ast
     }
 
-    pub fn use_(&self, visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use {
-        make::use_(visibility, use_tree).clone_for_update()
+    pub fn use_(
+        &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
+        visibility: Option<ast::Visibility>,
+        use_tree: ast::UseTree,
+    ) -> ast::Use {
+        make::use_(attrs, visibility, use_tree).clone_for_update()
     }
 
     pub fn use_tree(
@@ -840,16 +845,20 @@
 
     pub fn item_const(
         &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
         visibility: Option<ast::Visibility>,
         name: ast::Name,
         ty: ast::Type,
         expr: ast::Expr,
     ) -> ast::Const {
-        let ast = make::item_const(visibility.clone(), name.clone(), ty.clone(), expr.clone())
-            .clone_for_update();
+        let (attrs, attrs_input) = iterator_input(attrs);
+        let ast =
+            make::item_const(attrs, visibility.clone(), name.clone(), ty.clone(), expr.clone())
+                .clone_for_update();
 
         if let Some(mut mapping) = self.mappings() {
             let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone()));
             if let Some(visibility) = visibility {
                 builder.map_node(
                     visibility.syntax().clone(),
@@ -1067,6 +1076,7 @@
 
     pub fn item_enum(
         &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
         visibility: Option<ast::Visibility>,
         name: ast::Name,
         generic_param_list: Option<ast::GenericParamList>,
@@ -1074,6 +1084,7 @@
         variant_list: ast::VariantList,
     ) -> ast::Enum {
         let ast = make::enum_(
+            attrs,
             visibility.clone(),
             name.clone(),
             generic_param_list.clone(),
@@ -1182,6 +1193,7 @@
 
     pub fn fn_(
         &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
         visibility: Option<ast::Visibility>,
         fn_name: ast::Name,
         type_params: Option<ast::GenericParamList>,
@@ -1194,7 +1206,9 @@
         is_unsafe: bool,
         is_gen: bool,
     ) -> ast::Fn {
+        let (attrs, input) = iterator_input(attrs);
         let ast = make::fn_(
+            attrs,
             visibility.clone(),
             fn_name.clone(),
             type_params.clone(),
@@ -1210,6 +1224,7 @@
 
         if let Some(mut mapping) = self.mappings() {
             let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(input, ast.attrs().map(|attr| attr.syntax().clone()));
 
             if let Some(visibility) = visibility {
                 builder.map_node(
diff --git a/crates/syntax/src/syntax_editor.rs b/crates/syntax/src/syntax_editor.rs
index 18f5015..0b35887 100644
--- a/crates/syntax/src/syntax_editor.rs
+++ b/crates/syntax/src/syntax_editor.rs
@@ -619,6 +619,7 @@
     fn test_replace_token_in_parent() {
         let parent_fn = make::fn_(
             None,
+            None,
             make::name("it"),
             None,
             None,