Skip to content

Commit c79e24c

Browse files
committed
Migrate remove_dbg assist to use SyntaxEditor
1 parent e9968fc commit c79e24c

File tree

1 file changed

+44
-43
lines changed

1 file changed

+44
-43
lines changed

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

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use itertools::Itertools;
22
use syntax::{
3-
Edition, NodeOrToken, SyntaxElement, T, TextRange, TextSize,
4-
ast::{self, AstNode, AstToken, make},
5-
match_ast, ted,
3+
Edition, NodeOrToken, SyntaxNode, SyntaxToken, T,
4+
ast::{self, AstNode, make},
5+
match_ast,
6+
syntax_editor::{Position, SyntaxEditor},
67
};
78

89
use crate::{AssistContext, AssistId, Assists};
@@ -40,21 +41,23 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
4041

4142
let replacements =
4243
macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::<Vec<_>>();
43-
44-
acc.add(
45-
AssistId::quick_fix("remove_dbg"),
46-
"Remove dbg!()",
47-
replacements.iter().map(|&(range, _)| range).reduce(|acc, range| acc.cover(range))?,
48-
|builder| {
49-
for (range, expr) in replacements {
50-
if let Some(expr) = expr {
51-
builder.replace(range, expr.to_string());
52-
} else {
53-
builder.delete(range);
54-
}
44+
let target = replacements
45+
.iter()
46+
.flat_map(|(node_or_token, _)| node_or_token.iter())
47+
.map(|t| t.text_range())
48+
.reduce(|acc, range| acc.cover(range))?;
49+
acc.add(AssistId::quick_fix("remove_dbg"), "Remove dbg!()", target, |builder| {
50+
let mut editor = builder.make_editor(ctx.source_file().syntax());
51+
for (range, expr) in replacements {
52+
if let Some(expr) = expr {
53+
editor.insert(Position::before(range[0].clone()), expr.syntax().clone_for_update());
54+
}
55+
for node_or_token in range {
56+
editor.delete(node_or_token);
5557
}
56-
},
57-
)
58+
}
59+
builder.add_file_edits(ctx.vfs_file_id(), editor);
60+
})
5861
}
5962

6063
/// Returns `None` when either
@@ -63,7 +66,9 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
6366
/// - (`macro_expr` has no parent - is that possible?)
6467
///
6568
/// Returns `Some(_, None)` when the macro call should just be removed.
66-
fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Option<ast::Expr>)> {
69+
fn compute_dbg_replacement(
70+
macro_expr: ast::MacroExpr,
71+
) -> Option<(Vec<NodeOrToken<SyntaxNode, SyntaxToken>>, Option<ast::Expr>)> {
6772
let macro_call = macro_expr.macro_call()?;
6873
let tt = macro_call.token_tree()?;
6974
let r_delim = NodeOrToken::Token(tt.right_delimiter_token()?);
@@ -88,22 +93,22 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
8893
match_ast! {
8994
match parent {
9095
ast::StmtList(_) => {
91-
let range = macro_expr.syntax().text_range();
92-
let range = match whitespace_start(macro_expr.syntax().prev_sibling_or_token()) {
93-
Some(start) => range.cover_offset(start),
94-
None => range,
95-
};
96-
(range, None)
96+
let mut replace = vec![macro_expr.syntax().clone().into()];
97+
if let Some(prev_sibling) = macro_expr.syntax().prev_sibling_or_token()
98+
&& prev_sibling.kind() == syntax::SyntaxKind::WHITESPACE {
99+
replace.push(prev_sibling);
100+
}
101+
(replace, None)
97102
},
98103
ast::ExprStmt(it) => {
99-
let range = it.syntax().text_range();
100-
let range = match whitespace_start(it.syntax().prev_sibling_or_token()) {
101-
Some(start) => range.cover_offset(start),
102-
None => range,
103-
};
104-
(range, None)
104+
let mut replace = vec![it.syntax().clone().into()];
105+
if let Some(prev_sibling) = it.syntax().prev_sibling_or_token()
106+
&& prev_sibling.kind() == syntax::SyntaxKind::WHITESPACE {
107+
replace.push(prev_sibling);
108+
}
109+
(replace, None)
105110
},
106-
_ => (macro_call.syntax().text_range(), Some(make::ext::expr_unit())),
111+
_ => (vec![macro_call.syntax().clone().into()], Some(make::ext::expr_unit())),
107112
}
108113
}
109114
}
@@ -147,13 +152,13 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
147152
};
148153
let expr = replace_nested_dbgs(expr.clone());
149154
let expr = if wrap { make::expr_paren(expr).into() } else { expr.clone_subtree() };
150-
(macro_call.syntax().text_range(), Some(expr))
155+
(vec![macro_call.syntax().clone().into()], Some(expr))
151156
}
152157
// dbg!(expr0, expr1, ...)
153158
exprs => {
154159
let exprs = exprs.iter().cloned().map(replace_nested_dbgs);
155160
let expr = make::expr_tuple(exprs);
156-
(macro_call.syntax().text_range(), Some(expr.into()))
161+
(vec![macro_call.syntax().clone().into()], Some(expr.into()))
157162
}
158163
})
159164
}
@@ -178,8 +183,8 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
178183
return replaced;
179184
}
180185

181-
let expanded = expanded.clone_for_update();
182-
186+
let expanded = expanded.clone_subtree();
187+
let mut editor = SyntaxEditor::new(expanded.syntax().clone());
183188
// We need to collect to avoid mutation during traversal.
184189
let macro_exprs: Vec<_> =
185190
expanded.syntax().descendants().filter_map(ast::MacroExpr::cast).collect();
@@ -191,17 +196,13 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
191196
};
192197

193198
if let Some(expr) = expr_opt {
194-
ted::replace(mac.syntax(), expr.syntax().clone_for_update());
199+
editor.replace(mac.syntax(), expr.syntax().clone_for_update());
195200
} else {
196-
ted::remove(mac.syntax());
201+
editor.delete(mac.syntax());
197202
}
198203
}
199-
200-
expanded
201-
}
202-
203-
fn whitespace_start(it: Option<SyntaxElement>) -> Option<TextSize> {
204-
Some(it?.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start())
204+
let expanded_syntax = editor.finish().new_root().clone();
205+
ast::Expr::cast(expanded_syntax).unwrap()
205206
}
206207

207208
#[cfg(test)]

0 commit comments

Comments
 (0)