1
1
use itertools:: Itertools ;
2
2
use syntax:: {
3
3
ast:: { self , make, AstNode , AstToken } ,
4
- match_ast, ted, Edition , NodeOrToken , SyntaxElement , TextRange , TextSize , T ,
4
+ match_ast,
5
+ syntax_editor:: SyntaxEditor ,
6
+ Edition , NodeOrToken , SyntaxElement , TextRange , TextSize , T ,
5
7
} ;
6
8
7
9
use crate :: { AssistContext , AssistId , AssistKind , Assists } ;
@@ -37,22 +39,18 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
37
39
. collect ( )
38
40
} ;
39
41
40
- let replacements =
41
- macro_calls. into_iter ( ) . filter_map ( compute_dbg_replacement) . collect :: < Vec < _ > > ( ) ;
42
+ let root = match ctx. covering_element ( ) {
43
+ NodeOrToken :: Node ( node) => node. ancestors ( ) . last ( ) . unwrap ( ) ,
44
+ NodeOrToken :: Token ( token) => token. parent_ancestors ( ) . last ( ) . unwrap ( ) ,
45
+ } ;
46
+ let mut editor = SyntaxEditor :: new ( root) ;
47
+ let replacements = macro_calls. iter ( ) . filter_map ( |mc| run_dbg_replacement ( mc, & mut editor) ) ;
42
48
43
49
acc. add (
44
50
AssistId ( "remove_dbg" , AssistKind :: QuickFix ) ,
45
51
"Remove dbg!()" ,
46
- replacements. iter ( ) . map ( |& ( range, _) | range) . reduce ( |acc, range| acc. cover ( range) ) ?,
47
- |builder| {
48
- for ( range, expr) in replacements {
49
- if let Some ( expr) = expr {
50
- builder. replace ( range, expr. to_string ( ) ) ;
51
- } else {
52
- builder. delete ( range) ;
53
- }
54
- }
55
- } ,
52
+ replacements. map ( |( range, _) | range) . reduce ( |acc, range| acc. cover ( range) ) ?,
53
+ |builder| builder. add_file_edits ( ctx. file_id ( ) , editor) ,
56
54
)
57
55
}
58
56
@@ -62,7 +60,10 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
62
60
/// - (`macro_expr` has no parent - is that possible?)
63
61
///
64
62
/// Returns `Some(_, None)` when the macro call should just be removed.
65
- fn compute_dbg_replacement ( macro_expr : ast:: MacroExpr ) -> Option < ( TextRange , Option < ast:: Expr > ) > {
63
+ fn run_dbg_replacement (
64
+ macro_expr : & ast:: MacroExpr ,
65
+ editor : & mut SyntaxEditor ,
66
+ ) -> Option < ( TextRange , Option < ast:: Expr > ) > {
66
67
let macro_call = macro_expr. macro_call ( ) ?;
67
68
let tt = macro_call. token_tree ( ) ?;
68
69
let r_delim = NodeOrToken :: Token ( tt. right_delimiter_token ( ) ?) ;
@@ -92,6 +93,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
92
93
Some ( start) => range. cover_offset( start) ,
93
94
None => range,
94
95
} ;
96
+ editor. delete( macro_expr. syntax( ) . clone_for_update( ) ) ;
95
97
( range, None )
96
98
} ,
97
99
ast:: ExprStmt ( it) => {
@@ -100,15 +102,18 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
100
102
Some ( start) => range. cover_offset( start) ,
101
103
None => range,
102
104
} ;
105
+ editor. delete( macro_expr. syntax( ) . clone_for_update( ) ) ;
103
106
( range, None )
104
107
} ,
105
- _ => ( macro_call. syntax( ) . text_range( ) , Some ( make:: ext:: expr_unit( ) ) ) ,
108
+ _ => {
109
+ editor. replace( macro_call. syntax( ) , make:: ext:: expr_unit( ) . syntax( ) . clone_for_update( ) ) ;
110
+ ( macro_call. syntax( ) . text_range( ) , Some ( make:: ext:: expr_unit( ) ) )
111
+ } ,
106
112
}
107
113
}
108
114
}
109
115
// dbg!(expr0)
110
116
[ expr] => {
111
- // dbg!(expr, &parent);
112
117
let wrap = match ast:: Expr :: cast ( parent) {
113
118
Some ( parent) => match ( expr, parent) {
114
119
( ast:: Expr :: CastExpr ( _) , ast:: Expr :: CastExpr ( _) ) => false ,
@@ -144,25 +149,27 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
144
149
} ,
145
150
None => false ,
146
151
} ;
147
- let expr = replace_nested_dbgs ( expr. clone ( ) ) ;
148
- let expr = if wrap { make:: expr_paren ( expr) } else { expr. clone_subtree ( ) } ;
152
+ let expr = replace_nested_dbgs ( expr. clone ( ) , editor) ;
153
+ let expr = if wrap { make:: expr_paren ( expr. clone ( ) ) } else { expr. clone_subtree ( ) } ;
154
+ editor. replace ( macro_call. syntax ( ) , expr. syntax ( ) . clone_for_update ( ) ) ;
149
155
( macro_call. syntax ( ) . text_range ( ) , Some ( expr) )
150
156
}
151
157
// dbg!(expr0, expr1, ...)
152
158
exprs => {
153
- let exprs = exprs. iter ( ) . cloned ( ) . map ( replace_nested_dbgs) ;
159
+ let exprs = exprs. iter ( ) . map ( |expr| replace_nested_dbgs ( expr . clone ( ) , editor ) ) ;
154
160
let expr = make:: expr_tuple ( exprs) ;
161
+ editor. replace ( macro_call. syntax ( ) , expr. syntax ( ) . clone_for_update ( ) ) ;
155
162
( macro_call. syntax ( ) . text_range ( ) , Some ( expr. into ( ) ) )
156
163
}
157
164
} )
158
165
}
159
166
160
- fn replace_nested_dbgs ( expanded : ast:: Expr ) -> ast:: Expr {
167
+ fn replace_nested_dbgs ( expanded : ast:: Expr , editor : & mut SyntaxEditor ) -> ast:: Expr {
161
168
if let ast:: Expr :: MacroExpr ( mac) = & expanded {
162
169
// Special-case when `expanded` itself is `dbg!()` since we cannot replace the whole tree
163
170
// with `ted`. It should be fairly rare as it means the user wrote `dbg!(dbg!(..))` but you
164
171
// never know how code ends up being!
165
- let replaced = if let Some ( ( _, expr_opt) ) = compute_dbg_replacement ( mac. clone ( ) ) {
172
+ let replaced = if let Some ( ( _, expr_opt) ) = run_dbg_replacement ( mac, editor ) {
166
173
match expr_opt {
167
174
Some ( expr) => expr,
168
175
None => {
@@ -177,22 +184,18 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
177
184
return replaced;
178
185
}
179
186
180
- let expanded = expanded. clone_for_update ( ) ;
181
-
182
- // We need to collect to avoid mutation during traversal.
183
- let macro_exprs: Vec < _ > =
184
- expanded. syntax ( ) . descendants ( ) . filter_map ( ast:: MacroExpr :: cast) . collect ( ) ;
187
+ let macro_exprs = expanded. syntax ( ) . descendants ( ) . filter_map ( ast:: MacroExpr :: cast) ;
185
188
186
189
for mac in macro_exprs {
187
- let expr_opt = match compute_dbg_replacement ( mac. clone ( ) ) {
190
+ let expr_opt = match run_dbg_replacement ( & mac, editor ) {
188
191
Some ( ( _, expr) ) => expr,
189
192
None => continue ,
190
193
} ;
191
194
192
195
if let Some ( expr) = expr_opt {
193
- ted :: replace ( mac. syntax ( ) , expr. syntax ( ) . clone_for_update ( ) ) ;
196
+ editor . replace ( mac. syntax ( ) , expr. syntax ( ) . clone_for_update ( ) ) ;
194
197
} else {
195
- ted :: remove ( mac. syntax ( ) ) ;
198
+ editor . delete ( mac. syntax ( ) ) ;
196
199
}
197
200
}
198
201
0 commit comments