Skip to content

Commit 2a06000

Browse files
authored
Merge pull request rust-lang#18551 from ShoyuVanilla/migrate-turbofish-assist
Migrate `add_turbo_fish` to `SyntaxEditor`
2 parents 0631f46 + f091ec6 commit 2a06000

File tree

2 files changed

+77
-24
lines changed

2 files changed

+77
-24
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use either::Either;
22
use ide_db::defs::{Definition, NameRefClass};
33
use syntax::{
4-
ast::{self, make, HasArgList, HasGenericArgs},
5-
ted, AstNode,
4+
ast::{self, make, syntax_factory::SyntaxFactory, HasArgList, HasGenericArgs},
5+
syntax_editor::Position,
6+
AstNode,
67
};
78

89
use crate::{
@@ -91,20 +92,34 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
9192
AssistId("add_type_ascription", AssistKind::RefactorRewrite),
9293
"Add `: _` before assignment operator",
9394
ident.text_range(),
94-
|edit| {
95-
let let_stmt = edit.make_mut(let_stmt);
95+
|builder| {
96+
let mut editor = builder.make_editor(let_stmt.syntax());
9697

9798
if let_stmt.semicolon_token().is_none() {
98-
ted::append_child(let_stmt.syntax(), make::tokens::semicolon());
99+
editor.insert(
100+
Position::last_child_of(let_stmt.syntax()),
101+
make::tokens::semicolon(),
102+
);
99103
}
100104

101105
let placeholder_ty = make::ty_placeholder().clone_for_update();
102106

103-
let_stmt.set_ty(Some(placeholder_ty.clone()));
104-
105-
if let Some(cap) = ctx.config.snippet_cap {
106-
edit.add_placeholder_snippet(cap, placeholder_ty);
107+
if let Some(pat) = let_stmt.pat() {
108+
let elements = vec![
109+
make::token(syntax::SyntaxKind::COLON).into(),
110+
make::token(syntax::SyntaxKind::WHITESPACE).into(),
111+
placeholder_ty.syntax().clone().into(),
112+
];
113+
editor.insert_all(Position::after(pat.syntax()), elements);
114+
if let Some(cap) = ctx.config.snippet_cap {
115+
editor.add_annotation(
116+
placeholder_ty.syntax(),
117+
builder.make_placeholder_snippet(cap),
118+
);
119+
}
107120
}
121+
122+
builder.add_file_edits(ctx.file_id(), editor);
108123
},
109124
)?
110125
} else {
@@ -123,38 +138,58 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
123138
AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
124139
"Add `::<>`",
125140
ident.text_range(),
126-
|edit| {
127-
edit.trigger_parameter_hints();
141+
|builder| {
142+
builder.trigger_parameter_hints();
143+
144+
let make = SyntaxFactory::new();
145+
let mut editor = match &turbofish_target {
146+
Either::Left(it) => builder.make_editor(it.syntax()),
147+
Either::Right(it) => builder.make_editor(it.syntax()),
148+
};
149+
150+
let fish_head = get_fish_head(&make, number_of_arguments);
128151

129-
let new_arg_list = match turbofish_target {
152+
match turbofish_target {
130153
Either::Left(path_segment) => {
131-
edit.make_mut(path_segment).get_or_create_generic_arg_list()
154+
if let Some(generic_arg_list) = path_segment.generic_arg_list() {
155+
editor.replace(generic_arg_list.syntax(), fish_head.syntax());
156+
} else {
157+
editor.insert(
158+
Position::last_child_of(path_segment.syntax()),
159+
fish_head.syntax(),
160+
);
161+
}
132162
}
133163
Either::Right(method_call) => {
134-
edit.make_mut(method_call).get_or_create_generic_arg_list()
164+
if let Some(generic_arg_list) = method_call.generic_arg_list() {
165+
editor.replace(generic_arg_list.syntax(), fish_head.syntax());
166+
} else {
167+
let position = if let Some(arg_list) = method_call.arg_list() {
168+
Position::before(arg_list.syntax())
169+
} else {
170+
Position::last_child_of(method_call.syntax())
171+
};
172+
editor.insert(position, fish_head.syntax());
173+
}
135174
}
136175
};
137176

138-
let fish_head = get_fish_head(number_of_arguments).clone_for_update();
139-
140-
// Note: we need to replace the `new_arg_list` instead of being able to use something like
141-
// `GenericArgList::add_generic_arg` as `PathSegment::get_or_create_generic_arg_list`
142-
// always creates a non-turbofish form generic arg list.
143-
ted::replace(new_arg_list.syntax(), fish_head.syntax());
144-
145177
if let Some(cap) = ctx.config.snippet_cap {
146178
for arg in fish_head.generic_args() {
147-
edit.add_placeholder_snippet(cap, arg)
179+
editor.add_annotation(arg.syntax(), builder.make_placeholder_snippet(cap));
148180
}
149181
}
182+
183+
editor.add_mappings(make.finish_with_mappings());
184+
builder.add_file_edits(ctx.file_id(), editor);
150185
},
151186
)
152187
}
153188

154189
/// This will create a turbofish generic arg list corresponding to the number of arguments
155-
fn get_fish_head(number_of_arguments: usize) -> ast::GenericArgList {
190+
fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList {
156191
let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into());
157-
make::turbofish_generic_arg_list(args)
192+
make.turbofish_generic_arg_list(args)
158193
}
159194

160195
#[cfg(test)]

src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,22 @@ impl SyntaxFactory {
133133

134134
ast
135135
}
136+
137+
pub fn turbofish_generic_arg_list(
138+
&self,
139+
args: impl IntoIterator<Item = ast::GenericArg> + Clone,
140+
) -> ast::GenericArgList {
141+
let ast = make::turbofish_generic_arg_list(args.clone()).clone_for_update();
142+
143+
if let Some(mut mapping) = self.mappings() {
144+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
145+
builder.map_children(
146+
args.into_iter().map(|arg| arg.syntax().clone()),
147+
ast.generic_args().map(|arg| arg.syntax().clone()),
148+
);
149+
builder.finish(&mut mapping);
150+
}
151+
152+
ast
153+
}
136154
}

0 commit comments

Comments
 (0)