Skip to content

Commit 803fb51

Browse files
Merge pull request #21866 from Shourya742/2026-03-24-migrate-generate-new
Replace direct use of make in generate_new with SyntaxFactory
2 parents afa488c + d9c8251 commit 803fb51

File tree

3 files changed

+78
-44
lines changed

3 files changed

+78
-44
lines changed

crates/ide-assists/src/handlers/generate_new.rs

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use ide_db::{
33
use_trivial_constructor::use_trivial_constructor,
44
};
55
use syntax::{
6-
ast::{self, AstNode, HasName, HasVisibility, StructKind, edit::AstNodeEdit, make},
6+
ast::{
7+
self, AstNode, HasName, HasVisibility, StructKind, edit::AstNodeEdit,
8+
syntax_factory::SyntaxFactory,
9+
},
710
syntax_editor::Position,
811
};
912

@@ -36,6 +39,7 @@ use crate::{
3639
pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
3740
let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
3841

42+
let make = SyntaxFactory::without_mappings();
3943
let field_list = match strukt.kind() {
4044
StructKind::Record(named) => {
4145
named.fields().filter_map(|f| Some((f.name()?, f.ty()?))).collect::<Vec<_>>()
@@ -55,7 +59,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
5559
Some(name) => name,
5660
None => name_generator.suggest_name(&format!("_{i}")),
5761
};
58-
Some((make::name(name.as_str()), f.ty()?))
62+
Some((make.name(name.as_str()), f.ty()?))
5963
})
6064
.collect::<Vec<_>>()
6165
}
@@ -70,6 +74,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
7074

7175
let target = strukt.syntax().text_range();
7276
acc.add(AssistId::generate("generate_new"), "Generate `new`", target, |builder| {
77+
let make = SyntaxFactory::with_mappings();
7378
let trivial_constructors = field_list
7479
.iter()
7580
.map(|(name, ty)| {
@@ -95,63 +100,63 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
95100
edition,
96101
)?;
97102

98-
Some((make::name_ref(&name.text()), Some(expr)))
103+
Some((make.name_ref(&name.text()), Some(expr)))
99104
})
100105
.collect::<Vec<_>>();
101106

102107
let params = field_list.iter().enumerate().filter_map(|(i, (name, ty))| {
103108
if trivial_constructors[i].is_none() {
104-
Some(make::param(make::ident_pat(false, false, name.clone()).into(), ty.clone()))
109+
Some(make.param(make.ident_pat(false, false, name.clone()).into(), ty.clone()))
105110
} else {
106111
None
107112
}
108113
});
109-
let params = make::param_list(None, params);
114+
let params = make.param_list(None, params);
110115

111116
let fields = field_list.iter().enumerate().map(|(i, (name, _))| {
112117
if let Some(constructor) = trivial_constructors[i].clone() {
113118
constructor
114119
} else {
115-
(make::name_ref(&name.text()), None)
120+
(make.name_ref(&name.text()), None)
116121
}
117122
});
118123

119124
let tail_expr: ast::Expr = match strukt.kind() {
120125
StructKind::Record(_) => {
121-
let fields = fields.map(|(name, expr)| make::record_expr_field(name, expr));
122-
let fields = make::record_expr_field_list(fields);
123-
make::record_expr(make::ext::ident_path("Self"), fields).into()
126+
let fields = fields.map(|(name, expr)| make.record_expr_field(name, expr));
127+
let fields = make.record_expr_field_list(fields);
128+
make.record_expr(make.ident_path("Self"), fields).into()
124129
}
125130
StructKind::Tuple(_) => {
126131
let args = fields.map(|(arg, expr)| {
127-
let arg = || make::expr_path(make::path_unqualified(make::path_segment(arg)));
132+
let arg = || make.expr_path(make.path_unqualified(make.path_segment(arg)));
128133
expr.unwrap_or_else(arg)
129134
});
130-
let arg_list = make::arg_list(args);
131-
make::expr_call(make::expr_path(make::ext::ident_path("Self")), arg_list).into()
135+
let arg_list = make.arg_list(args);
136+
make.expr_call(make.expr_path(make.ident_path("Self")), arg_list).into()
132137
}
133138
StructKind::Unit => unreachable!(),
134139
};
135-
let body = make::block_expr(None, tail_expr.into());
136-
137-
let ret_type = make::ret_type(make::ty_path(make::ext::ident_path("Self")));
138-
139-
let fn_ = make::fn_(
140-
None,
141-
strukt.visibility(),
142-
make::name("new"),
143-
None,
144-
None,
145-
params,
146-
body,
147-
Some(ret_type),
148-
false,
149-
false,
150-
false,
151-
false,
152-
)
153-
.clone_for_update()
154-
.indent(1.into());
140+
let body = make.block_expr(None, tail_expr.into());
141+
142+
let ret_type = make.ret_type(make.ty_path(make.ident_path("Self")).into());
143+
144+
let fn_ = make
145+
.fn_(
146+
[],
147+
strukt.visibility(),
148+
make.name("new"),
149+
None,
150+
None,
151+
params,
152+
body,
153+
Some(ret_type),
154+
false,
155+
false,
156+
false,
157+
false,
158+
)
159+
.indent(1.into());
155160

156161
let mut editor = builder.make_editor(strukt.syntax());
157162

@@ -164,32 +169,30 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
164169
editor.insert_all(
165170
Position::after(l_curly),
166171
vec![
167-
make::tokens::whitespace(&format!("\n{}", impl_def.indent_level() + 1))
168-
.into(),
172+
make.whitespace(&format!("\n{}", impl_def.indent_level() + 1)).into(),
169173
fn_.syntax().clone().into(),
170-
make::tokens::whitespace("\n").into(),
174+
make.whitespace("\n").into(),
171175
],
172176
);
173177
fn_.syntax().clone()
174178
} else {
175-
let items = vec![ast::AssocItem::Fn(fn_)];
176-
let list = make::assoc_item_list(Some(items));
179+
let list = make.assoc_item_list([ast::AssocItem::Fn(fn_)]);
177180
editor.insert(Position::after(impl_def.syntax()), list.syntax());
178181
list.syntax().clone()
179182
}
180183
} else {
181184
// Generate a new impl to add the method to
182185
let indent_level = strukt.indent_level();
183-
let body = vec![ast::AssocItem::Fn(fn_)];
184-
let list = make::assoc_item_list(Some(body));
185-
let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list))
186-
.indent(strukt.indent_level());
186+
let list = make.assoc_item_list([ast::AssocItem::Fn(fn_)]);
187+
let impl_def =
188+
generate_impl_with_item(&make, &ast::Adt::Struct(strukt.clone()), Some(list))
189+
.indent(strukt.indent_level());
187190

188191
// Insert it after the adt
189192
editor.insert_all(
190193
Position::after(strukt.syntax()),
191194
vec![
192-
make::tokens::whitespace(&format!("\n\n{indent_level}")).into(),
195+
make.whitespace(&format!("\n\n{indent_level}")).into(),
193196
impl_def.syntax().clone().into(),
194197
],
195198
);
@@ -233,6 +236,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
233236
}
234237
}
235238

239+
editor.add_mappings(make.finish_with_mappings());
236240
builder.add_file_edits(ctx.vfs_file_id(), editor);
237241
})
238242
}

crates/ide-assists/src/utils.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,10 +733,11 @@ fn generate_impl_text_inner(
733733
/// Generates the corresponding `impl Type {}` including type and lifetime
734734
/// parameters.
735735
pub(crate) fn generate_impl_with_item(
736+
make: &SyntaxFactory,
736737
adt: &ast::Adt,
737738
body: Option<ast::AssocItemList>,
738739
) -> ast::Impl {
739-
generate_impl_inner(false, adt, None, true, body)
740+
generate_impl_inner_with_factory(make, false, adt, None, true, body)
740741
}
741742

742743
pub(crate) fn generate_impl_with_factory(make: &SyntaxFactory, adt: &ast::Adt) -> ast::Impl {

crates/syntax/src/ast/syntax_factory/constructors.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1470,6 +1470,22 @@ impl SyntaxFactory {
14701470
ast
14711471
}
14721472

1473+
pub fn record_expr_field_list(
1474+
&self,
1475+
fields: impl IntoIterator<Item = ast::RecordExprField>,
1476+
) -> ast::RecordExprFieldList {
1477+
let (fields, input) = iterator_input(fields);
1478+
let ast = make::record_expr_field_list(fields).clone_for_update();
1479+
1480+
if let Some(mut mapping) = self.mappings() {
1481+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
1482+
builder.map_children(input, ast.fields().map(|f| f.syntax().clone()));
1483+
builder.finish(&mut mapping);
1484+
}
1485+
1486+
ast
1487+
}
1488+
14731489
pub fn record_expr_field(
14741490
&self,
14751491
name: ast::NameRef,
@@ -1480,7 +1496,20 @@ impl SyntaxFactory {
14801496
if let Some(mut mapping) = self.mappings() {
14811497
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
14821498

1483-
builder.map_node(name.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
1499+
if let Some(ast_name_ref) = ast.name_ref() {
1500+
// NameRef is a direct child
1501+
builder.map_node(name.syntax().clone(), ast_name_ref.syntax().clone());
1502+
} else {
1503+
// NameRef is nested inside PathExpr > Path > PathSegment.
1504+
// map_node requires the output to be a direct child of the builder's parent, so
1505+
// we need a separate builder scoped to PathSegment.
1506+
let ast::Expr::PathExpr(path_expr) = ast.expr().unwrap() else { unreachable!() };
1507+
let path_segment = path_expr.path().unwrap().segment().unwrap();
1508+
let inner_name_ref = path_segment.name_ref().unwrap();
1509+
let mut inner_builder = SyntaxMappingBuilder::new(path_segment.syntax().clone());
1510+
inner_builder.map_node(name.syntax().clone(), inner_name_ref.syntax().clone());
1511+
inner_builder.finish(&mut mapping);
1512+
}
14841513
if let Some(expr) = expr {
14851514
builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
14861515
}

0 commit comments

Comments
 (0)