11use ide_db:: { defs:: Definition , search:: FileReference , EditionedFileId } ;
22use syntax:: {
3- algo:: find_node_at_range,
3+ algo:: { find_node_at_range, least_common_ancestor_element } ,
44 ast:: { self , HasArgList } ,
5- AstNode , SourceFile , SyntaxKind , SyntaxNode , TextRange , T ,
5+ syntax_editor:: Element ,
6+ AstNode , SourceFile , SyntaxElement , SyntaxKind , SyntaxNode , TextRange , T ,
67} ;
78
89use SyntaxKind :: WHITESPACE ;
@@ -74,15 +75,21 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) ->
7475 cov_mark:: hit!( keep_used) ;
7576 return None ;
7677 }
78+ let parent = param. syntax ( ) . parent ( ) ?;
7779 acc. add (
7880 AssistId ( "remove_unused_param" , AssistKind :: Refactor ) ,
7981 "Remove unused parameter" ,
8082 param. syntax ( ) . text_range ( ) ,
8183 |builder| {
82- builder. delete ( range_to_remove ( param. syntax ( ) ) ) ;
84+ let mut editor = builder. make_editor ( & parent) ;
85+ let elements = elements_to_remove ( param. syntax ( ) ) ;
86+ for element in elements {
87+ editor. delete ( element) ;
88+ }
8389 for ( file_id, references) in fn_def. usages ( & ctx. sema ) . all ( ) {
8490 process_usages ( ctx, builder, file_id, references, param_position, is_self_present) ;
8591 }
92+ builder. add_file_edits ( ctx. file_id ( ) , editor) ;
8693 } ,
8794 )
8895}
@@ -96,20 +103,24 @@ fn process_usages(
96103 is_self_present : bool ,
97104) {
98105 let source_file = ctx. sema . parse ( file_id) ;
99- builder. edit_file ( file_id) ;
100106 let possible_ranges = references
101107 . into_iter ( )
102108 . filter_map ( |usage| process_usage ( & source_file, usage, arg_to_remove, is_self_present) ) ;
103109
104- let mut ranges_to_delete: Vec < TextRange > = vec ! [ ] ;
105- for range in possible_ranges {
106- if !ranges_to_delete. iter ( ) . any ( |it| it. contains_range ( range) ) {
107- ranges_to_delete. push ( range)
110+ for element_range in possible_ranges {
111+ let Some ( SyntaxElement :: Node ( parent) ) = element_range
112+ . iter ( )
113+ . cloned ( )
114+ . reduce ( |a, b| least_common_ancestor_element ( & a, & b) . unwrap ( ) . syntax_element ( ) )
115+ else {
116+ continue ;
117+ } ;
118+ let mut editor = builder. make_editor ( & parent) ;
119+ for element in element_range {
120+ editor. delete ( element) ;
108121 }
109- }
110122
111- for range in ranges_to_delete {
112- builder. delete ( range)
123+ builder. add_file_edits ( file_id, editor) ;
113124 }
114125}
115126
@@ -118,7 +129,7 @@ fn process_usage(
118129 FileReference { range, .. } : FileReference ,
119130 mut arg_to_remove : usize ,
120131 is_self_present : bool ,
121- ) -> Option < TextRange > {
132+ ) -> Option < Vec < SyntaxElement > > {
122133 let call_expr_opt: Option < ast:: CallExpr > = find_node_at_range ( source_file. syntax ( ) , range) ;
123134 if let Some ( call_expr) = call_expr_opt {
124135 let call_expr_range = call_expr. expr ( ) ?. syntax ( ) . text_range ( ) ;
@@ -127,7 +138,7 @@ fn process_usage(
127138 }
128139
129140 let arg = call_expr. arg_list ( ) ?. args ( ) . nth ( arg_to_remove) ?;
130- return Some ( range_to_remove ( arg. syntax ( ) ) ) ;
141+ return Some ( elements_to_remove ( arg. syntax ( ) ) ) ;
131142 }
132143
133144 let method_call_expr_opt: Option < ast:: MethodCallExpr > =
@@ -143,7 +154,7 @@ fn process_usage(
143154 }
144155
145156 let arg = method_call_expr. arg_list ( ) ?. args ( ) . nth ( arg_to_remove) ?;
146- return Some ( range_to_remove ( arg. syntax ( ) ) ) ;
157+ return Some ( elements_to_remove ( arg. syntax ( ) ) ) ;
147158 }
148159
149160 None
@@ -174,6 +185,29 @@ pub(crate) fn range_to_remove(node: &SyntaxNode) -> TextRange {
174185 }
175186}
176187
188+ pub ( crate ) fn elements_to_remove ( node : & SyntaxNode ) -> Vec < SyntaxElement > {
189+ let up_to_comma = next_prev ( ) . find_map ( |dir| {
190+ node. siblings_with_tokens ( dir)
191+ . filter_map ( |it| it. into_token ( ) )
192+ . find ( |it| it. kind ( ) == T ! [ , ] )
193+ . map ( |it| ( dir, it) )
194+ } ) ;
195+ if let Some ( ( dir, token) ) = up_to_comma {
196+ let after = token. siblings_with_tokens ( dir) . nth ( 1 ) . unwrap ( ) ;
197+ let mut result: Vec < _ > =
198+ node. siblings_with_tokens ( dir) . take_while ( |it| it != & after) . collect ( ) ;
199+ if node. next_sibling ( ) . is_some ( ) {
200+ result. extend (
201+ token. siblings_with_tokens ( dir) . skip ( 1 ) . take_while ( |it| it. kind ( ) == WHITESPACE ) ,
202+ ) ;
203+ }
204+
205+ result
206+ } else {
207+ vec ! [ node. syntax_element( ) ]
208+ }
209+ }
210+
177211#[ cfg( test) ]
178212mod tests {
179213 use crate :: tests:: { check_assist, check_assist_not_applicable} ;
0 commit comments