Skip to content

internal: migrate extract_module to SyntaxEditor#21868

Open
itang06 wants to merge 2 commits into
rust-lang:masterfrom
itang06:feature/US-18285-extract-module-syntax-editor
Open

internal: migrate extract_module to SyntaxEditor#21868
itang06 wants to merge 2 commits into
rust-lang:masterfrom
itang06:feature/US-18285-extract-module-syntax-editor

Conversation

@itang06
Copy link
Copy Markdown

@itang06 itang06 commented Mar 25, 2026

Part of #18285

Migrates all ted:: calls in crates/ide-assists/src/handlers/extract_module.rs to the new SyntaxEditor/SyntaxFactory abstraction

Changes:

  • generate_module_def: replaced ted:: with SyntaxEditor/SyntaxFactory
  • expand_and_group_usages_file_wise: replaced ted::replace with SyntaxEditor
  • change_visibility: replaced ted::insert (via add_change_vis helper) with SyntaxEditor::insert_all; removes the add_change_vis function entirely

AI assistance was used for this contribution

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 25, 2026
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please migrate remaining make::* usages to SyntaxFactory APIs

continue;
}

let mut editor = SyntaxEditor::new(body_item.syntax().clone());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this new SyntaxEditor instance and .finish() call on it necessary? Couldn't it be done by passing the mutable reference of existing one from the assist entrance function as a parameter of this function instead?

Copy link
Copy Markdown
Author

@itang06 itang06 Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the items here are detached clone_subtree() nodes, so the editor from the entry point can't reach them. I can use SyntaxFactory::without_mappings() locally to get rid of the .clone_for_update() calls instead, does that work?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yeah, I guess it could be still uplifted to the root SyntaxEditor but that would require more involved refactoring, so I think this is fine as is for now

})
.collect();
if !replacements.is_empty() {
let mut editor = SyntaxEditor::new(entry.syntax().clone());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, too

@@ -18,8 +18,10 @@ use syntax::{
self, HasVisibility,
edit::{AstNodeEdit, IndentLevel},
make,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kindly replace use of make with SyntaxFactory

let assoc_item_list = make::assoc_item_list(Some(assoc_items)).clone_for_update();
let impl_ = impl_.reset_indent();
ted::replace(impl_.get_or_create_assoc_item_list().syntax(), assoc_item_list.syntax());
let impl_detached = ast::Impl::cast(impl_.syntax().clone_subtree()).unwrap();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unwraps

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?


let (mut replacements, record_field_parents, impls) =
get_replacements_for_visibility_change(&mut self.body_items, false);
get_replacements_for_visibility_change(&mut self.body_items, true);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Copy Markdown
Author

@itang06 itang06 Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was a workaround because of the local SyntaxEditor approach, was an incorrect change


let mut editor = SyntaxEditor::new(body_item.syntax().clone());
for target in insert_targets {
let pub_crate_vis = make::visibility_pub_crate().clone_for_update();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be removed?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix, good catch

Some((
seg.syntax().parent()?,
make::path_from_text(&format!("{mod_name}::{seg}"))
.clone_for_update(),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i missed that this should use SyntaxFactory, will replace it

@ChayimFriedman2
Copy link
Copy Markdown
Contributor

@itang06 What's the status of this?

@itang06
Copy link
Copy Markdown
Author

itang06 commented Apr 9, 2026

@itang06 What's the status of this?

i addressed the unwrap issue. waiting for ShoyuVanilla's response to my question about using SyntaxFactory::without_mappings() locally in the helpers instead of passing the file-level editor since they operate on detached nodes

@itang06 itang06 force-pushed the feature/US-18285-extract-module-syntax-editor branch from 11ff3da to fbf2dfa Compare April 11, 2026 08:14
@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@itang06 itang06 force-pushed the feature/US-18285-extract-module-syntax-editor branch from fbf2dfa to a9d2246 Compare April 11, 2026 08:31
@rustbot

This comment has been minimized.

.entry(use_.syntax().text_range().start())
.or_insert_with(|| use_.clone_subtree().clone_for_update());
for seg in use_
.or_insert_with(|| use_.clone_subtree());
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View changes since the review

remove clone_subtree

let assoc_item_list = make::assoc_item_list(Some(assoc_items)).clone_for_update();
let impl_ = impl_.reset_indent();
ted::replace(impl_.get_or_create_assoc_item_list().syntax(), assoc_item_list.syntax());
let impl_detached = ast::Impl::cast(impl_.syntax().clone_subtree()).unwrap();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

],
);
}
*body_item = ast::Item::cast(editor.finish().new_root().clone_subtree()).unwrap();
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View changes since the review

Suggested change
*body_item = ast::Item::cast(editor.finish().new_root().clone_subtree()).unwrap();
*body_item = ast::Item::cast(editor.finish().new_root()).unwrap();

Comment on lines +435 to +437
for item in &mut self.body_items {
*item = ast::Item::cast(item.reset_indent().syntax().clone_subtree()).unwrap();
}
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View changes since the review

No need to call clone_subtree here anymore. SyntaxEditor manages this internally

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i tried removing the clone_subtree() calls but found that 3 of the 4 calls require using the detached root returned by SyntaxEditor::new() instead of just dropping clone_subtree(). i think the 4th at line 436 has to stay because replacements is collected from body_items immediately after. is there something i'm missing or is there a different approach you had in mind?

@ChayimFriedman2
Copy link
Copy Markdown
Contributor

@itang06 What's the status of this?

@itang06
Copy link
Copy Markdown
Author

itang06 commented Apr 26, 2026

@itang06 What's the status of this?

waiting on feedback from Shourya742 regarding the approach for removing clone_subtree() calls (see my comment above). all tests pass but i just need confirmation on the direction before committing

@Shourya742
Copy link
Copy Markdown
Member

Hey @itang06, can you rebase the changes onto the latest master? A lot of the semantics around syntaxEditor have changed. The clone_subtree issue can be resolved using a local editor.

@Shourya742
Copy link
Copy Markdown
Member

Can you also please squash the commits, seems like most are changing the same file.

@Shourya742
Copy link
Copy Markdown
Member

Hey @itang06 are you still working on this?

@itang06
Copy link
Copy Markdown
Author

itang06 commented May 10, 2026

Yes, still working on it. i'll have an update soon.

@Shourya742
Copy link
Copy Markdown
Member

Make sure to remove/update ted variant of get_or_create_assoc_item_list from edit-in-place .

@itang06 itang06 force-pushed the feature/US-18285-extract-module-syntax-editor branch from 74c1a1e to de6c326 Compare May 13, 2026 08:44
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented May 13, 2026

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented May 13, 2026

⚠️ Warning ⚠️

  • There are uncanonicalized issue links (such as #123) in the commit messages of the following commits.
    Please add the organization and repository before the issue number (like so rust-lang/rust#123) to avoid issues with subtree.

@itang06
Copy link
Copy Markdown
Author

itang06 commented May 13, 2026

@Shourya742 i found that after rebasing. removing the clone_subtree() calls causes is_ancestor_or_self_of_element to fail, since when SyntaxEditor::new() clones internally, the node references collected before the editor was created end up pointing to the wrong tree. would the fix be to collect targets from the editor's detached root instead?

@itang06 itang06 force-pushed the feature/US-18285-extract-module-syntax-editor branch from de6c326 to 7b0b9c7 Compare May 13, 2026 08:56
@Shourya742
Copy link
Copy Markdown
Member

@Shourya742 i found that after rebasing. removing the clone_subtree() calls causes is_ancestor_or_self_of_element to fail, since when SyntaxEditor::new() clones internally, the node references collected before the editor was created end up pointing to the wrong tree. would the fix be to collect targets from the editor's detached root instead?

Yes

@itang06 itang06 force-pushed the feature/US-18285-extract-module-syntax-editor branch 2 times, most recently from f828748 to 5b44119 Compare May 17, 2026 09:34
_ => true,
}
});
let make = SyntaxFactory::without_mappings();
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to initialize the without_mappining here, you can get it from the editor and have mapped changes stored in the factory.

View changes since the review

Copy link
Copy Markdown
Author

@itang06 itang06 May 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, using editor.make() in a scoped block so it's dropped before editor.finish()

let (_, root) = SyntaxEditor::with_ast_node(&use_);
root
});
let make = SyntaxFactory::without_mappings();
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use the make via the editor

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, simplified to use_.clone()

@@ -741,7 +788,6 @@

fn get_replacements_for_visibility_change(
items: &mut [ast::Item],
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are not longer mutating it.

Suggested change
items: &mut [ast::Item],
items: &[ast::Item],

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


let (mut replacements, record_field_parents, impls) =
get_replacements_for_visibility_change(&mut self.body_items, false);
get_replacements_for_visibility_change(&mut self.body_items);
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont need mut here now.

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


let (mut impl_item_replacements, _, _) =
get_replacements_for_visibility_change(&mut impl_items, true);
get_replacements_for_visibility_change(&mut impl_items);
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need mut here now.

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines +186 to +190
@@ -186,6 +187,7 @@
parent_impl: &Option<ast::Impl>,
Module { name, body_items, use_items }: &Module,
) -> ast::Module {
let make = SyntaxFactory::without_mappings();
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can pass factory to generate_module_def method from extract_module

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. also did the same for make_use_stmt_of_node_with_super and change_visibility which had the same issue

imports_to_remove
}

fn process_def_in_sel(
Copy link
Copy Markdown
Member

@Shourya742 Shourya742 May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can pass factory to process_def_in_sel

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, threaded it through resolve_imports

@itang06 itang06 force-pushed the feature/US-18285-extract-module-syntax-editor branch from 5b44119 to 563cdc6 Compare May 22, 2026 08:40
@Shourya742
Copy link
Copy Markdown
Member

Pinging @ChayimFriedman2, for a final look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants