Merge pull request #20137 from Hmikihiro/migrate-wrap_unwrap_cfg_attr-assist-to-syntaxeditor

Migrate `wrap_unwrap_cfg_attr` Assist to use `SyntaxEditor`
diff --git a/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs b/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs
index e1b9467..5183566 100644
--- a/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs
+++ b/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs
@@ -2,8 +2,7 @@
 use itertools::Itertools;
 use syntax::{
     NodeOrToken, SyntaxToken, T, TextRange, algo,
-    ast::{self, AstNode, make},
-    ted::{self, Position},
+    ast::{self, AstNode, make, syntax_factory::SyntaxFactory},
 };
 
 use crate::{AssistContext, AssistId, Assists};
@@ -173,40 +172,45 @@
         }
     }
     let handle_source_change = |edit: &mut SourceChangeBuilder| {
-        let new_derive = make::attr_outer(make::meta_token_tree(
-            make::ext::ident_path("derive"),
-            make::token_tree(T!['('], new_derive),
-        ))
-        .clone_for_update();
-        let meta = make::meta_token_tree(
-            make::ext::ident_path("cfg_attr"),
-            make::token_tree(
+        let make = SyntaxFactory::with_mappings();
+        let mut editor = edit.make_editor(attr.syntax());
+        let new_derive = make.attr_outer(
+            make.meta_token_tree(make.ident_path("derive"), make.token_tree(T!['('], new_derive)),
+        );
+        let meta = make.meta_token_tree(
+            make.ident_path("cfg_attr"),
+            make.token_tree(
                 T!['('],
                 vec![
-                    NodeOrToken::Token(make::token(T![,])),
-                    NodeOrToken::Token(make::tokens::whitespace(" ")),
-                    NodeOrToken::Token(make::tokens::ident("derive")),
-                    NodeOrToken::Node(make::token_tree(T!['('], cfg_derive_tokens)),
+                    NodeOrToken::Token(make.token(T![,])),
+                    NodeOrToken::Token(make.whitespace(" ")),
+                    NodeOrToken::Token(make.ident("derive")),
+                    NodeOrToken::Node(make.token_tree(T!['('], cfg_derive_tokens)),
                 ],
             ),
         );
-        // Remove the derive attribute
-        let edit_attr = edit.make_syntax_mut(attr.syntax().clone());
 
-        ted::replace(edit_attr, new_derive.syntax().clone());
-        let cfg_attr = make::attr_outer(meta).clone_for_update();
-
-        ted::insert_all_raw(
-            Position::after(new_derive.syntax().clone()),
-            vec![make::tokens::whitespace("\n").into(), cfg_attr.syntax().clone().into()],
+        let cfg_attr = make.attr_outer(meta);
+        editor.replace_with_many(
+            attr.syntax(),
+            vec![
+                new_derive.syntax().clone().into(),
+                make.whitespace("\n").into(),
+                cfg_attr.syntax().clone().into(),
+            ],
         );
+
         if let Some(snippet_cap) = ctx.config.snippet_cap {
             if let Some(first_meta) =
                 cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
             {
-                edit.add_tabstop_after_token(snippet_cap, first_meta)
+                let tabstop = edit.make_tabstop_after(snippet_cap);
+                editor.add_annotation(first_meta, tabstop);
             }
         }
+
+        editor.add_mappings(make.finish_with_mappings());
+        edit.add_file_edits(ctx.vfs_file_id(), editor);
     };
 
     acc.add(
@@ -221,10 +225,10 @@
     let range = attr.syntax().text_range();
     let path = attr.path()?;
     let handle_source_change = |edit: &mut SourceChangeBuilder| {
-        let mut raw_tokens = vec![
-            NodeOrToken::Token(make::token(T![,])),
-            NodeOrToken::Token(make::tokens::whitespace(" ")),
-        ];
+        let make = SyntaxFactory::with_mappings();
+        let mut editor = edit.make_editor(attr.syntax());
+        let mut raw_tokens =
+            vec![NodeOrToken::Token(make.token(T![,])), NodeOrToken::Token(make.whitespace(" "))];
         path.syntax().descendants_with_tokens().for_each(|it| {
             if let NodeOrToken::Token(token) = it {
                 raw_tokens.push(NodeOrToken::Token(token));
@@ -232,9 +236,9 @@
         });
         if let Some(meta) = attr.meta() {
             if let (Some(eq), Some(expr)) = (meta.eq_token(), meta.expr()) {
-                raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" ")));
+                raw_tokens.push(NodeOrToken::Token(make.whitespace(" ")));
                 raw_tokens.push(NodeOrToken::Token(eq));
-                raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" ")));
+                raw_tokens.push(NodeOrToken::Token(make.whitespace(" ")));
 
                 expr.syntax().descendants_with_tokens().for_each(|it| {
                     if let NodeOrToken::Token(token) = it {
@@ -245,26 +249,24 @@
                 raw_tokens.extend(tt.token_trees_and_tokens());
             }
         }
-        let meta = make::meta_token_tree(
-            make::ext::ident_path("cfg_attr"),
-            make::token_tree(T!['('], raw_tokens),
-        );
-        let cfg_attr = if attr.excl_token().is_some() {
-            make::attr_inner(meta)
-        } else {
-            make::attr_outer(meta)
-        }
-        .clone_for_update();
-        let attr_syntax = edit.make_syntax_mut(attr.syntax().clone());
-        ted::replace(attr_syntax, cfg_attr.syntax());
+        let meta =
+            make.meta_token_tree(make.ident_path("cfg_attr"), make.token_tree(T!['('], raw_tokens));
+        let cfg_attr =
+            if attr.excl_token().is_some() { make.attr_inner(meta) } else { make.attr_outer(meta) };
+
+        editor.replace(attr.syntax(), cfg_attr.syntax());
 
         if let Some(snippet_cap) = ctx.config.snippet_cap {
             if let Some(first_meta) =
                 cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
             {
-                edit.add_tabstop_after_token(snippet_cap, first_meta)
+                let tabstop = edit.make_tabstop_after(snippet_cap);
+                editor.add_annotation(first_meta, tabstop);
             }
         }
+
+        editor.add_mappings(make.finish_with_mappings());
+        edit.add_file_edits(ctx.vfs_file_id(), editor);
     };
     acc.add(
         AssistId::refactor("wrap_unwrap_cfg_attr"),
diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs
index 429e51b..17cc5f9 100644
--- a/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -1212,6 +1212,43 @@
         ast
     }
 
+    pub fn attr_outer(&self, meta: ast::Meta) -> ast::Attr {
+        let ast = make::attr_outer(meta.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(meta.syntax().clone(), ast.meta().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn attr_inner(&self, meta: ast::Meta) -> ast::Attr {
+        let ast = make::attr_inner(meta.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(meta.syntax().clone(), ast.meta().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn meta_token_tree(&self, path: ast::Path, tt: ast::TokenTree) -> ast::Meta {
+        let ast = make::meta_token_tree(path.clone(), tt.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone());
+            builder.map_node(tt.syntax().clone(), ast.token_tree().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn token_tree(
         &self,
         delimiter: SyntaxKind,
@@ -1242,6 +1279,10 @@
     pub fn whitespace(&self, text: &str) -> SyntaxToken {
         make::tokens::whitespace(text)
     }
+
+    pub fn ident(&self, text: &str) -> SyntaxToken {
+        make::tokens::ident(text)
+    }
 }
 
 // `ext` constructors