Skip to content

Commit f627fc7

Browse files
committed
Migrate remove unused imports to SYntaxEditor
1 parent 87d7d78 commit f627fc7

3 files changed

Lines changed: 63 additions & 32 deletions

File tree

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,24 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_, '
111111
is_path_per_ns_unused_in_scope(ctx, &u, scope, &res).then_some(u)
112112
}
113113
})
114-
.peekable();
114+
.collect::<Vec<_>>();
115115

116-
// Peek so we terminate early if an unused use is found. Only do the rest of the work if the user selects the assist.
117-
if unused.peek().is_some() {
116+
// Terminate early unless an unused use is found. Only do the rest of the work if the user selects the assist.
117+
if !unused.is_empty() {
118118
acc.add(
119119
AssistId::quick_fix("remove_unused_imports"),
120120
"Remove all unused imports",
121121
selected_el.text_range(),
122122
|builder| {
123-
let unused: Vec<ast::UseTree> = unused.map(|x| builder.make_mut(x)).collect();
124-
for node in unused {
125-
node.remove_recursive();
123+
let editor = builder.make_editor(&selected_el);
124+
unused.sort_by_key(|use_tree| use_tree.syntax().text_range().start());
125+
for node in &unused {
126+
editor.delete(node.syntax());
126127
}
128+
for node in unused.iter().cloned() {
129+
node.remove_recursive(&editor);
130+
}
131+
builder.add_file_edits(ctx.vfs_file_id(), editor);
127132
},
128133
)
129134
} else {

crates/syntax/src/ast/edit_in_place.rs

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,24 +56,41 @@ impl Removable for ast::UseTree {
5656
}
5757

5858
impl ast::UseTree {
59+
/// Editor variant of UseTree remove
60+
fn remove_with_editor(&self, editor: &SyntaxEditor) {
61+
for dir in [Direction::Next, Direction::Prev] {
62+
if let Some(next_use_tree) = neighbor(self, dir) {
63+
let separators = self
64+
.syntax()
65+
.siblings_with_tokens(dir)
66+
.skip(1)
67+
.take_while(|it| it.as_node() != Some(next_use_tree.syntax()));
68+
for separator in separators {
69+
editor.delete(separator);
70+
}
71+
break;
72+
}
73+
}
74+
editor.delete(self.syntax());
75+
}
76+
5977
/// Deletes the usetree node represented by the input. Recursively removes parents, including use nodes that become empty.
60-
pub fn remove_recursive(self) {
78+
pub fn remove_recursive(self, editor: &SyntaxEditor) {
6179
let parent = self.syntax().parent();
6280

63-
self.remove();
64-
6581
if let Some(u) = parent.clone().and_then(ast::Use::cast) {
66-
if u.use_tree().is_none() {
67-
u.remove();
68-
}
82+
u.remove(editor);
6983
} else if let Some(u) = parent.and_then(ast::UseTreeList::cast) {
70-
if u.use_trees().next().is_none() {
71-
let parent = u.syntax().parent().and_then(ast::UseTree::cast);
72-
if let Some(u) = parent {
73-
u.remove_recursive();
74-
}
84+
if u.use_trees().nth(1).is_none()
85+
|| u.use_trees().all(|use_tree| {
86+
use_tree.syntax() == self.syntax() || editor.deleted(use_tree.syntax())
87+
})
88+
{
89+
u.parent_use_tree().remove_recursive(editor);
90+
return;
7591
}
76-
u.remove_unnecessary_braces();
92+
self.remove_with_editor(editor);
93+
u.remove_unnecessary_braces(editor);
7794
}
7895
}
7996

@@ -224,8 +241,9 @@ impl ast::UseTreeList {
224241
}
225242
}
226243

227-
impl Removable for ast::Use {
228-
fn remove(&self) {
244+
impl ast::Use {
245+
fn remove(&self, editor: &SyntaxEditor) {
246+
let make = editor.make();
229247
let next_ws = self
230248
.syntax()
231249
.next_sibling_or_token()
@@ -234,10 +252,17 @@ impl Removable for ast::Use {
234252
if let Some(next_ws) = next_ws {
235253
let ws_text = next_ws.syntax().text();
236254
if let Some(rest) = ws_text.strip_prefix('\n') {
237-
if rest.is_empty() {
238-
ted::remove(next_ws.syntax());
255+
let next_use_removed = next_ws
256+
.syntax()
257+
.next_sibling_or_token()
258+
.and_then(|it| it.into_node())
259+
.and_then(ast::Use::cast)
260+
.and_then(|use_| use_.use_tree())
261+
.is_some_and(|use_tree| editor.deleted(use_tree.syntax()));
262+
if rest.is_empty() || next_use_removed {
263+
editor.delete(next_ws.syntax());
239264
} else {
240-
ted::replace(next_ws.syntax(), make::tokens::whitespace(rest));
265+
editor.replace(next_ws.syntax(), make.whitespace(rest));
241266
}
242267
}
243268
}
@@ -251,13 +276,13 @@ impl Removable for ast::Use {
251276
let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0);
252277
let rest = &ws_text[0..prev_newline];
253278
if rest.is_empty() {
254-
ted::remove(prev_ws.syntax());
279+
editor.delete(prev_ws.syntax());
255280
} else {
256-
ted::replace(prev_ws.syntax(), make::tokens::whitespace(rest));
281+
editor.replace(prev_ws.syntax(), make.whitespace(rest));
257282
}
258283
}
259284

260-
ted::remove(self.syntax());
285+
editor.delete(self.syntax());
261286
}
262287
}
263288

crates/syntax/src/ast/node_ext.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::{
1616
self, AstNode, AstToken, HasAttrs, HasGenericArgs, HasGenericParams, HasName,
1717
HasTypeBounds, SyntaxNode, support,
1818
},
19-
ted,
19+
syntax_editor::SyntaxEditor,
2020
};
2121

2222
use super::{GenericParam, RangeItem, RangeOp};
@@ -454,11 +454,12 @@ impl ast::UseTreeList {
454454
}
455455

456456
/// Remove the unnecessary braces in current `UseTreeList`
457-
pub fn remove_unnecessary_braces(mut self) {
457+
pub fn remove_unnecessary_braces(mut self, editor: &SyntaxEditor) {
458458
// Returns true iff there is a single subtree and it is not the self keyword. The braces in
459459
// `use x::{self};` are necessary and so we should not remove them.
460460
let has_single_subtree_that_is_not_self = |u: &ast::UseTreeList| {
461-
if let Some((single_subtree,)) = u.use_trees().collect_tuple() {
461+
let use_trees = u.use_trees().filter(|use_tree| !editor.deleted(use_tree.syntax()));
462+
if let Some((single_subtree,)) = use_trees.collect_tuple() {
462463
// We have a single subtree, check whether it is self.
463464

464465
let is_self = single_subtree.path().as_ref().is_some_and(|path| {
@@ -476,12 +477,12 @@ impl ast::UseTreeList {
476477
let remove_brace_in_use_tree_list = |u: &ast::UseTreeList| {
477478
if has_single_subtree_that_is_not_self(u) {
478479
if let Some(a) = u.l_curly_token() {
479-
ted::remove(a)
480+
editor.delete(a)
480481
}
481482
if let Some(a) = u.r_curly_token() {
482-
ted::remove(a)
483+
editor.delete(a)
483484
}
484-
u.comma().for_each(ted::remove);
485+
u.comma().for_each(|u| editor.delete(u));
485486
}
486487
};
487488

0 commit comments

Comments
 (0)