@@ -27,6 +27,27 @@ pub use ide_db::rename::RenameError;
2727
2828type RenameResult < T > = Result < T , RenameError > ;
2929
30+ /// This is similar to `collect::<Result<Vec<_>, _>>`, but unlike it, it succeeds if there is *any* `Ok` item.
31+ fn ok_if_any < T , E > ( iter : impl Iterator < Item = Result < T , E > > ) -> Result < Vec < T > , E > {
32+ let mut err = None ;
33+ let oks = iter
34+ . filter_map ( |item| match item {
35+ Ok ( it) => Some ( it) ,
36+ Err ( it) => {
37+ err = Some ( it) ;
38+ None
39+ }
40+ } )
41+ . collect :: < Vec < _ > > ( ) ;
42+ if !oks. is_empty ( ) {
43+ Ok ( oks)
44+ } else if let Some ( err) = err {
45+ Err ( err)
46+ } else {
47+ Ok ( Vec :: new ( ) )
48+ }
49+ }
50+
3051/// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is
3152/// being targeted for a rename.
3253pub ( crate ) fn prepare_rename (
@@ -95,58 +116,57 @@ pub(crate) fn rename(
95116 alias_fallback ( syntax, position, & new_name. display ( db, edition) . to_string ( ) ) ;
96117
97118 let ops: RenameResult < Vec < SourceChange > > = match alias_fallback {
98- Some ( _) => defs
99- // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can
100- // properly find "direct" usages/references.
101- . map ( |( .., def, new_name, _) | {
102- match kind {
103- IdentifierKind :: Ident => ( ) ,
104- IdentifierKind :: Lifetime => {
105- bail ! ( "Cannot alias reference to a lifetime identifier" )
106- }
107- IdentifierKind :: Underscore => bail ! ( "Cannot alias reference to `_`" ) ,
108- IdentifierKind :: LowercaseSelf => {
109- bail ! ( "Cannot rename alias reference to `self`" )
110- }
111- } ;
112- let mut usages = def. usages ( & sema) . all ( ) ;
113-
114- // FIXME: hack - removes the usage that triggered this rename operation.
115- match usages. references . get_mut ( & file_id) . and_then ( |refs| {
116- refs. iter ( )
117- . position ( |ref_| ref_. range . contains_inclusive ( position. offset ) )
118- . map ( |idx| refs. remove ( idx) )
119- } ) {
120- Some ( _) => ( ) ,
121- None => never ! ( ) ,
122- } ;
123-
124- let mut source_change = SourceChange :: default ( ) ;
125- source_change. extend ( usages. references . get_mut ( & file_id) . iter ( ) . map ( |refs| {
126- (
127- position. file_id ,
128- source_edit_from_references ( db, refs, def, & new_name, edition) ,
129- )
130- } ) ) ;
131-
132- Ok ( source_change)
133- } )
134- . collect ( ) ,
135- None => defs
136- . map ( |( .., def, new_name, rename_def) | {
137- if let Definition :: Local ( local) = def {
138- if let Some ( self_param) = local. as_self_param ( sema. db ) {
139- cov_mark:: hit!( rename_self_to_param) ;
140- return rename_self_to_param ( & sema, local, self_param, & new_name, kind) ;
141- }
142- if kind == IdentifierKind :: LowercaseSelf {
143- cov_mark:: hit!( rename_to_self) ;
144- return rename_to_self ( & sema, local) ;
145- }
119+ Some ( _) => ok_if_any (
120+ defs
121+ // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can
122+ // properly find "direct" usages/references.
123+ . map ( |( .., def, new_name, _) | {
124+ match kind {
125+ IdentifierKind :: Ident => ( ) ,
126+ IdentifierKind :: Lifetime => {
127+ bail ! ( "Cannot alias reference to a lifetime identifier" )
128+ }
129+ IdentifierKind :: Underscore => bail ! ( "Cannot alias reference to `_`" ) ,
130+ IdentifierKind :: LowercaseSelf => {
131+ bail ! ( "Cannot rename alias reference to `self`" )
132+ }
133+ } ;
134+ let mut usages = def. usages ( & sema) . all ( ) ;
135+
136+ // FIXME: hack - removes the usage that triggered this rename operation.
137+ match usages. references . get_mut ( & file_id) . and_then ( |refs| {
138+ refs. iter ( )
139+ . position ( |ref_| ref_. range . contains_inclusive ( position. offset ) )
140+ . map ( |idx| refs. remove ( idx) )
141+ } ) {
142+ Some ( _) => ( ) ,
143+ None => never ! ( ) ,
144+ } ;
145+
146+ let mut source_change = SourceChange :: default ( ) ;
147+ source_change. extend ( usages. references . get_mut ( & file_id) . iter ( ) . map ( |refs| {
148+ (
149+ position. file_id ,
150+ source_edit_from_references ( db, refs, def, & new_name, edition) ,
151+ )
152+ } ) ) ;
153+
154+ Ok ( source_change)
155+ } ) ,
156+ ) ,
157+ None => ok_if_any ( defs. map ( |( .., def, new_name, rename_def) | {
158+ if let Definition :: Local ( local) = def {
159+ if let Some ( self_param) = local. as_self_param ( sema. db ) {
160+ cov_mark:: hit!( rename_self_to_param) ;
161+ return rename_self_to_param ( & sema, local, self_param, & new_name, kind) ;
146162 }
147- def. rename ( & sema, new_name. as_str ( ) , rename_def)
148- } )
149- . collect ( ) ,
163+ if kind == IdentifierKind :: LowercaseSelf {
164+ cov_mark:: hit!( rename_to_self) ;
165+ return rename_to_self ( & sema, local) ;
166+ }
167+ }
168+ def. rename ( & sema, new_name. as_str ( ) , rename_def)
169+ } ) ) ,
150170 } ;
151171
152172 ops?. into_iter ( )
@@ -320,7 +340,7 @@ fn find_definitions(
320340 } )
321341 } ) ;
322342
323- let res: RenameResult < Vec < _ > > = symbols. filter_map ( Result :: transpose) . collect ( ) ;
343+ let res: RenameResult < Vec < _ > > = ok_if_any ( symbols. filter_map ( Result :: transpose) ) ;
324344 match res {
325345 Ok ( v) => {
326346 // remove duplicates, comparing `Definition`s
0 commit comments