11use itertools:: Itertools ;
22use 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
89use 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