Skip to content

Commit 7b0b9c7

Browse files
committed
internal: migrate extract_module assist to SyntaxEditor
1 parent 7d2e672 commit 7b0b9c7

2 files changed

Lines changed: 82 additions & 62 deletions

File tree

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

Lines changed: 82 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ fn generate_module_def(
187187
parent_impl: &Option<ast::Impl>,
188188
Module { name, body_items, use_items }: &Module,
189189
) -> ast::Module {
190+
let make = SyntaxFactory::without_mappings();
190191
let items: Vec<_> = if let Some(impl_) = parent_impl.as_ref()
191192
&& let Some(self_ty) = impl_.self_ty()
192193
{
@@ -196,9 +197,13 @@ fn generate_module_def(
196197
.filter_map(ast::AssocItem::cast)
197198
.map(|it| it.indent(IndentLevel(1)))
198199
.collect_vec();
199-
let assoc_item_list = make::assoc_item_list(Some(assoc_items)).clone_for_update();
200-
let impl_ = impl_.reset_indent();
201-
ted::replace(impl_.get_or_create_assoc_item_list().syntax(), assoc_item_list.syntax());
200+
let impl_reset = impl_.reset_indent();
201+
let (editor, impl_root) = SyntaxEditor::with_ast_node(&impl_reset);
202+
let assoc_item_list = editor.make().assoc_item_list(assoc_items);
203+
if let Some(existing_list) = impl_root.assoc_item_list() {
204+
editor.replace(existing_list.syntax(), assoc_item_list.syntax());
205+
}
206+
let impl_ = ast::Impl::cast(editor.finish().new_root().clone()).unwrap();
202207
// Add the import for enum/struct corresponding to given impl block
203208
let use_impl = make_use_stmt_of_node_with_super(self_ty.syntax());
204209
once(use_impl)
@@ -210,19 +215,19 @@ fn generate_module_def(
210215
};
211216

212217
let items = items.into_iter().map(|it| it.reset_indent().indent(IndentLevel(1))).collect_vec();
213-
let module_body = make::item_list(Some(items));
214-
215-
let module_name = make::name(name);
216-
make::mod_(module_name, Some(module_body))
218+
let module_body = make.item_list(items);
219+
let module_name = make.name(name);
220+
make.mod_(module_name, Some(module_body))
217221
}
218222

219223
fn make_use_stmt_of_node_with_super(node_syntax: &SyntaxNode) -> ast::Item {
220-
let super_path = make::ext::ident_path("super");
221-
let node_path = make::ext::ident_path(&node_syntax.to_string());
222-
let use_ = make::use_(
223-
None,
224+
let make = SyntaxFactory::without_mappings();
225+
let super_path = make.ident_path("super");
226+
let node_path = make.path_from_text(&node_syntax.to_string());
227+
let use_ = make.use_(
228+
[],
224229
None,
225-
make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false),
230+
make.use_tree(make.path_concat(super_path, node_path), None, None, false),
226231
);
227232

228233
ast::Item::from(use_)
@@ -386,18 +391,28 @@ impl Module {
386391
if use_.syntax().parent().is_some_and(|parent| parent == covering_node)
387392
&& use_stmts_set.insert(use_.syntax().text_range().start())
388393
{
389-
let use_ = use_stmts_to_be_inserted
394+
let entry = use_stmts_to_be_inserted
390395
.entry(use_.syntax().text_range().start())
391-
.or_insert_with(|| use_.clone_subtree().clone_for_update());
392-
for seg in use_
396+
.or_insert_with(|| use_.clone_subtree());
397+
let make = SyntaxFactory::without_mappings();
398+
let replacements: Vec<_> = entry
393399
.syntax()
394400
.descendants()
395401
.filter_map(ast::NameRef::cast)
396402
.filter(|seg| seg.syntax().to_string() == name_ref.to_string())
397-
{
398-
let new_ref = make::path_from_text(&format!("{mod_name}::{seg}"))
399-
.clone_for_update();
400-
ted::replace(seg.syntax().parent()?, new_ref.syntax());
403+
.filter_map(|seg| {
404+
Some((
405+
seg.syntax().parent()?,
406+
make.path_from_text(&format!("{mod_name}::{seg}")),
407+
))
408+
})
409+
.collect();
410+
if !replacements.is_empty() {
411+
let (editor, _) = SyntaxEditor::new(entry.syntax().clone());
412+
for (parent, new_ref) in &replacements {
413+
editor.replace(parent, new_ref.syntax());
414+
}
415+
*entry = ast::Use::cast(editor.finish().new_root().clone()).unwrap();
401416
}
402417
}
403418
}
@@ -409,8 +424,12 @@ impl Module {
409424
}
410425

411426
fn change_visibility(&mut self, record_fields: Vec<SyntaxNode>) {
427+
for item in &mut self.body_items {
428+
*item = ast::Item::cast(item.reset_indent().syntax().clone_subtree()).unwrap();
429+
}
430+
412431
let (mut replacements, record_field_parents, impls) =
413-
get_replacements_for_visibility_change(&mut self.body_items, false);
432+
get_replacements_for_visibility_change(&mut self.body_items);
414433

415434
let mut impl_items = impls
416435
.into_iter()
@@ -419,7 +438,7 @@ impl Module {
419438
.collect_vec();
420439

421440
let (mut impl_item_replacements, _, _) =
422-
get_replacements_for_visibility_change(&mut impl_items, true);
441+
get_replacements_for_visibility_change(&mut impl_items);
423442

424443
replacements.append(&mut impl_item_replacements);
425444

@@ -433,17 +452,40 @@ impl Module {
433452
}
434453
}
435454

436-
for (vis, syntax) in replacements {
437-
let item = syntax.children_with_tokens().find(|node_or_token| {
438-
match node_or_token.kind() {
439-
// We're skipping comments, doc comments, and attribute macros that may precede the keyword
440-
// that the visibility should be placed before.
441-
SyntaxKind::COMMENT | SyntaxKind::ATTR | SyntaxKind::WHITESPACE => false,
442-
_ => true,
443-
}
444-
});
455+
let make = SyntaxFactory::without_mappings();
456+
for body_item in &mut self.body_items {
457+
let insert_targets: Vec<_> = replacements
458+
.iter()
459+
.filter(|(vis, syntax)| {
460+
vis.is_none()
461+
&& (syntax == body_item.syntax()
462+
|| syntax.ancestors().any(|a| &a == body_item.syntax()))
463+
})
464+
.filter_map(|(_, syntax)| {
465+
syntax.children_with_tokens().find(|nt| {
466+
!matches!(
467+
nt.kind(),
468+
SyntaxKind::COMMENT | SyntaxKind::ATTR | SyntaxKind::WHITESPACE
469+
)
470+
})
471+
})
472+
.collect();
445473

446-
add_change_vis(vis, item);
474+
if insert_targets.is_empty() {
475+
continue;
476+
}
477+
478+
let (editor, _) = SyntaxEditor::new(body_item.syntax().clone());
479+
for target in insert_targets {
480+
editor.insert_all(
481+
Position::before(target),
482+
vec![
483+
make.visibility_pub_crate().syntax().clone().into(),
484+
make.whitespace(" ").into(),
485+
],
486+
);
487+
}
488+
*body_item = ast::Item::cast(editor.finish().new_root().clone()).unwrap();
447489
}
448490
}
449491

@@ -494,6 +536,7 @@ impl Module {
494536
curr_parent_module: &Option<ast::Module>,
495537
ctx: &AssistContext<'_, '_>,
496538
) -> Option<TextRange> {
539+
let make = SyntaxFactory::without_mappings();
497540
//We only need to find in the current file
498541
let selection_range = ctx.selection_trimmed();
499542
let file_id = ctx.file_id();
@@ -591,7 +634,7 @@ impl Module {
591634
if !first_path_in_use_tree_str.contains("super")
592635
&& !first_path_in_use_tree_str.contains("crate")
593636
{
594-
let super_path = make::ext::ident_path("super");
637+
let super_path = make.ident_path("super");
595638
use_tree_str.push(super_path);
596639
}
597640
}
@@ -610,7 +653,7 @@ impl Module {
610653
&& let Some(first_path_in_use_tree) = use_tree_paths.first()
611654
&& first_path_in_use_tree.to_string().contains("super")
612655
{
613-
use_tree_paths.insert(0, make::ext::ident_path("super"));
656+
use_tree_paths.insert(0, make.ident_path("super"));
614657
}
615658

616659
let is_item = matches!(
@@ -625,12 +668,12 @@ impl Module {
625668
| Definition::TypeAlias(_)
626669
);
627670

628-
if (def_out_sel || !is_item) && use_stmt_not_in_sel {
629-
let use_ = make::use_(
630-
None,
631-
None,
632-
make::use_tree(make::join_paths(use_tree_paths), None, None, false),
633-
);
671+
if (def_out_sel || !is_item)
672+
&& use_stmt_not_in_sel
673+
&& let Some(joined) =
674+
use_tree_paths.into_iter().reduce(|acc, p| make.path_concat(acc, p))
675+
{
676+
let use_ = make.use_([], None, make.use_tree(joined, None, None, false));
634677
self.use_items.insert(0, ast::Item::from(use_));
635678
}
636679
}
@@ -742,7 +785,6 @@ fn check_def_in_mod_and_out_sel(
742785

743786
fn get_replacements_for_visibility_change(
744787
items: &mut [ast::Item],
745-
is_clone_for_updated: bool,
746788
) -> (
747789
Vec<(Option<ast::Visibility>, SyntaxNode)>,
748790
Vec<(Option<ast::Visibility>, SyntaxNode)>,
@@ -753,9 +795,6 @@ fn get_replacements_for_visibility_change(
753795
let mut impls = Vec::new();
754796

755797
for item in items {
756-
if !is_clone_for_updated {
757-
*item = item.clone_for_update();
758-
}
759798
//Use stmts are ignored
760799
macro_rules! push_to_replacement {
761800
($it:ident) => {
@@ -812,15 +851,6 @@ fn get_use_tree_paths_from_path(
812851
Some(use_tree_str)
813852
}
814853

815-
fn add_change_vis(vis: Option<ast::Visibility>, node_or_token_opt: Option<syntax::SyntaxElement>) {
816-
if vis.is_none()
817-
&& let Some(node_or_token) = node_or_token_opt
818-
{
819-
let pub_crate_vis = make::visibility_pub_crate().clone_for_update();
820-
ted::insert(ted::Position::before(node_or_token), pub_crate_vis.syntax());
821-
}
822-
}
823-
824854
fn indent_range_before_given_node(node: &SyntaxNode) -> Option<TextRange> {
825855
node.siblings_with_tokens(syntax::Direction::Prev)
826856
.find(|x| x.kind() == WHITESPACE)

crates/syntax/src/ast/edit_in_place.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -286,16 +286,6 @@ impl ast::Use {
286286
}
287287
}
288288

289-
impl ast::Impl {
290-
pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList {
291-
if self.assoc_item_list().is_none() {
292-
let assoc_item_list = make::assoc_item_list(None).clone_for_update();
293-
ted::append_child(self.syntax(), assoc_item_list.syntax());
294-
}
295-
self.assoc_item_list().unwrap()
296-
}
297-
}
298-
299289
impl ast::RecordExprField {
300290
/// This will either replace the initializer, or in the case that this is a shorthand convert
301291
/// the initializer into the name ref and insert the expr as the new initializer.

0 commit comments

Comments
 (0)