about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorShoyu Vanilla <modulo641@gmail.com>2024-11-25 01:01:50 +0900
committerShoyu Vanilla <modulo641@gmail.com>2024-11-26 01:47:15 +0900
commitf091ec669e3f46bbf62048cb2a4b42ea5d9536ad (patch)
tree6c833d23d552ab3bae52df54f2fc70684ddd3160 /src
parent309c671083006dcc5b16dd023f90cb91d4230002 (diff)
downloadrust-f091ec669e3f46bbf62048cb2a4b42ea5d9536ad.tar.gz
rust-f091ec669e3f46bbf62048cb2a4b42ea5d9536ad.zip
Migrate `add_turbo_fish` to `SyntaxEditor`
Diffstat (limited to 'src')
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs83
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs18
2 files changed, 77 insertions, 24 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
index 17efbcbd6c9..0f6970d9403 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
@@ -1,8 +1,9 @@
 use either::Either;
 use ide_db::defs::{Definition, NameRefClass};
 use syntax::{
-    ast::{self, make, HasArgList, HasGenericArgs},
-    ted, AstNode,
+    ast::{self, make, syntax_factory::SyntaxFactory, HasArgList, HasGenericArgs},
+    syntax_editor::Position,
+    AstNode,
 };
 
 use crate::{
@@ -91,20 +92,34 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
                 AssistId("add_type_ascription", AssistKind::RefactorRewrite),
                 "Add `: _` before assignment operator",
                 ident.text_range(),
-                |edit| {
-                    let let_stmt = edit.make_mut(let_stmt);
+                |builder| {
+                    let mut editor = builder.make_editor(let_stmt.syntax());
 
                     if let_stmt.semicolon_token().is_none() {
-                        ted::append_child(let_stmt.syntax(), make::tokens::semicolon());
+                        editor.insert(
+                            Position::last_child_of(let_stmt.syntax()),
+                            make::tokens::semicolon(),
+                        );
                     }
 
                     let placeholder_ty = make::ty_placeholder().clone_for_update();
 
-                    let_stmt.set_ty(Some(placeholder_ty.clone()));
-
-                    if let Some(cap) = ctx.config.snippet_cap {
-                        edit.add_placeholder_snippet(cap, placeholder_ty);
+                    if let Some(pat) = let_stmt.pat() {
+                        let elements = vec![
+                            make::token(syntax::SyntaxKind::COLON).into(),
+                            make::token(syntax::SyntaxKind::WHITESPACE).into(),
+                            placeholder_ty.syntax().clone().into(),
+                        ];
+                        editor.insert_all(Position::after(pat.syntax()), elements);
+                        if let Some(cap) = ctx.config.snippet_cap {
+                            editor.add_annotation(
+                                placeholder_ty.syntax(),
+                                builder.make_placeholder_snippet(cap),
+                            );
+                        }
                     }
+
+                    builder.add_file_edits(ctx.file_id(), editor);
                 },
             )?
         } else {
@@ -123,38 +138,58 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
         AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
         "Add `::<>`",
         ident.text_range(),
-        |edit| {
-            edit.trigger_parameter_hints();
+        |builder| {
+            builder.trigger_parameter_hints();
+
+            let make = SyntaxFactory::new();
+            let mut editor = match &turbofish_target {
+                Either::Left(it) => builder.make_editor(it.syntax()),
+                Either::Right(it) => builder.make_editor(it.syntax()),
+            };
+
+            let fish_head = get_fish_head(&make, number_of_arguments);
 
-            let new_arg_list = match turbofish_target {
+            match turbofish_target {
                 Either::Left(path_segment) => {
-                    edit.make_mut(path_segment).get_or_create_generic_arg_list()
+                    if let Some(generic_arg_list) = path_segment.generic_arg_list() {
+                        editor.replace(generic_arg_list.syntax(), fish_head.syntax());
+                    } else {
+                        editor.insert(
+                            Position::last_child_of(path_segment.syntax()),
+                            fish_head.syntax(),
+                        );
+                    }
                 }
                 Either::Right(method_call) => {
-                    edit.make_mut(method_call).get_or_create_generic_arg_list()
+                    if let Some(generic_arg_list) = method_call.generic_arg_list() {
+                        editor.replace(generic_arg_list.syntax(), fish_head.syntax());
+                    } else {
+                        let position = if let Some(arg_list) = method_call.arg_list() {
+                            Position::before(arg_list.syntax())
+                        } else {
+                            Position::last_child_of(method_call.syntax())
+                        };
+                        editor.insert(position, fish_head.syntax());
+                    }
                 }
             };
 
-            let fish_head = get_fish_head(number_of_arguments).clone_for_update();
-
-            // Note: we need to replace the `new_arg_list` instead of being able to use something like
-            // `GenericArgList::add_generic_arg` as `PathSegment::get_or_create_generic_arg_list`
-            // always creates a non-turbofish form generic arg list.
-            ted::replace(new_arg_list.syntax(), fish_head.syntax());
-
             if let Some(cap) = ctx.config.snippet_cap {
                 for arg in fish_head.generic_args() {
-                    edit.add_placeholder_snippet(cap, arg)
+                    editor.add_annotation(arg.syntax(), builder.make_placeholder_snippet(cap));
                 }
             }
+
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.file_id(), editor);
         },
     )
 }
 
 /// This will create a turbofish generic arg list corresponding to the number of arguments
-fn get_fish_head(number_of_arguments: usize) -> ast::GenericArgList {
+fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList {
     let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into());
-    make::turbofish_generic_arg_list(args)
+    make.turbofish_generic_arg_list(args)
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 9f88add0f78..6e90b2ba47f 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -107,4 +107,22 @@ impl SyntaxFactory {
 
         ast
     }
+
+    pub fn turbofish_generic_arg_list(
+        &self,
+        args: impl IntoIterator<Item = ast::GenericArg> + Clone,
+    ) -> ast::GenericArgList {
+        let ast = make::turbofish_generic_arg_list(args.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(
+                args.into_iter().map(|arg| arg.syntax().clone()),
+                ast.generic_args().map(|arg| arg.syntax().clone()),
+            );
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
 }