1- use ide_db:: text_edit:: TextRange ;
21use ide_db:: {
32 assists:: { AssistId , AssistKind } ,
43 defs:: Definition ,
5- search:: { FileReference , SearchScope , UsageSearchResult } ,
4+ search:: { FileReference , SearchScope } ,
5+ syntax_helpers:: suggest_name,
6+ text_edit:: TextRange ,
67} ;
78use itertools:: Itertools ;
9+ use syntax:: SmolStr ;
810use syntax:: {
911 ast:: { self , make, AstNode , FieldExpr , HasName , IdentPat } ,
1012 ted,
@@ -122,33 +124,43 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleDat
122124 return None ;
123125 }
124126
125- let name = ident_pat. name ( ) ?. to_string ( ) ;
126-
127- let usages = ctx. sema . to_def ( & ident_pat) . map ( |def| {
127+ let usages = ctx. sema . to_def ( & ident_pat) . and_then ( |def| {
128128 Definition :: Local ( def)
129129 . usages ( & ctx. sema )
130130 . in_scope ( & SearchScope :: single_file ( ctx. file_id ( ) ) )
131131 . all ( )
132+ . iter ( )
133+ . next ( )
134+ . map ( |( _, refs) | refs. to_vec ( ) )
132135 } ) ;
133136
134- let field_names = ( 0 ..field_types. len ( ) )
135- . map ( |i| generate_name ( ctx, i, & name, & ident_pat, & usages) )
137+ let mut name_generator = {
138+ let mut names = vec ! [ ] ;
139+ if let Some ( scope) = ctx. sema . scope ( ident_pat. syntax ( ) ) {
140+ scope. process_all_names ( & mut |name, scope| {
141+ if let hir:: ScopeDef :: Local ( _) = scope {
142+ names. push ( name. as_str ( ) . into ( ) )
143+ }
144+ } )
145+ }
146+ suggest_name:: NameGenerator :: new_with_names ( names. iter ( ) . map ( |s : & SmolStr | s. as_str ( ) ) )
147+ } ;
148+
149+ let field_names = field_types
150+ . into_iter ( )
151+ . enumerate ( )
152+ . map ( |( id, ty) | {
153+ match name_generator. for_type ( & ty, ctx. db ( ) , ctx. edition ( ) ) {
154+ Some ( name) => name,
155+ None => name_generator. suggest_name ( & format ! ( "_{}" , id) ) ,
156+ }
157+ . to_string ( )
158+ } )
136159 . collect :: < Vec < _ > > ( ) ;
137160
138161 Some ( TupleData { ident_pat, ref_type, field_names, usages } )
139162}
140163
141- fn generate_name (
142- _ctx : & AssistContext < ' _ > ,
143- index : usize ,
144- _tuple_name : & str ,
145- _ident_pat : & IdentPat ,
146- _usages : & Option < UsageSearchResult > ,
147- ) -> String {
148- // FIXME: detect if name already used
149- format ! ( "_{index}" )
150- }
151-
152164enum RefType {
153165 ReadOnly ,
154166 Mutable ,
@@ -157,7 +169,7 @@ struct TupleData {
157169 ident_pat : IdentPat ,
158170 ref_type : Option < RefType > ,
159171 field_names : Vec < String > ,
160- usages : Option < UsageSearchResult > ,
172+ usages : Option < Vec < FileReference > > ,
161173}
162174fn edit_tuple_assignment (
163175 ctx : & AssistContext < ' _ > ,
@@ -213,42 +225,23 @@ fn edit_tuple_usages(
213225 ctx : & AssistContext < ' _ > ,
214226 in_sub_pattern : bool ,
215227) -> Option < Vec < EditTupleUsage > > {
216- let mut current_file_usages = None ;
217-
218- if let Some ( usages) = data. usages . as_ref ( ) {
219- // We need to collect edits first before actually applying them
220- // as mapping nodes to their mutable node versions requires an
221- // unmodified syntax tree.
222- //
223- // We also defer editing usages in the current file first since
224- // tree mutation in the same file breaks when `builder.edit_file`
225- // is called
226-
227- if let Some ( ( _, refs) ) = usages. iter ( ) . find ( |( file_id, _) | * file_id == ctx. file_id ( ) ) {
228- current_file_usages = Some (
229- refs. iter ( )
230- . filter_map ( |r| edit_tuple_usage ( ctx, edit, r, data, in_sub_pattern) )
231- . collect_vec ( ) ,
232- ) ;
233- }
234-
235- for ( file_id, refs) in usages. iter ( ) {
236- if file_id == ctx. file_id ( ) {
237- continue ;
238- }
239-
240- edit. edit_file ( file_id. file_id ( ) ) ;
241-
242- let tuple_edits = refs
243- . iter ( )
244- . filter_map ( |r| edit_tuple_usage ( ctx, edit, r, data, in_sub_pattern) )
245- . collect_vec ( ) ;
246-
247- tuple_edits. into_iter ( ) . for_each ( |tuple_edit| tuple_edit. apply ( edit) )
248- }
249- }
250-
251- current_file_usages
228+ // We need to collect edits first before actually applying them
229+ // as mapping nodes to their mutable node versions requires an
230+ // unmodified syntax tree.
231+ //
232+ // We also defer editing usages in the current file first since
233+ // tree mutation in the same file breaks when `builder.edit_file`
234+ // is called
235+
236+ let edits = data
237+ . usages
238+ . as_ref ( ) ?
239+ . as_slice ( )
240+ . iter ( )
241+ . filter_map ( |r| edit_tuple_usage ( ctx, edit, r, data, in_sub_pattern) )
242+ . collect_vec ( ) ;
243+
244+ Some ( edits)
252245}
253246fn edit_tuple_usage (
254247 ctx : & AssistContext < ' _ > ,
@@ -1769,14 +1762,14 @@ struct S4 {
17691762}
17701763
17711764fn foo() -> Option<()> {
1772- let ($0_0, _1, _2, _3, _4 , _5) = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
1765+ let ($0_0, _1, _2, _3, s4 , _5) = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
17731766 let v: i32 = *_0; // deref, no parens
17741767 let v: &i32 = _0; // no deref, no parens, remove `&`
17751768 f1(*_0); // deref, no parens
17761769 f2(_0); // `&*` -> cancel out -> no deref, no parens
17771770 // https://github.com/rust-lang/rust-analyzer/issues/1109#issuecomment-658868639
17781771 // let v: i32 = t.1.0; // no deref, no parens
1779- let v: i32 = _4 .value; // no deref, no parens
1772+ let v: i32 = s4 .value; // no deref, no parens
17801773 (*_0).do_stuff(); // deref, parens
17811774 let v: i32 = (*_2)?; // deref, parens
17821775 let v: i32 = _3[0]; // no deref, no parens
@@ -1815,8 +1808,8 @@ impl S {
18151808}
18161809
18171810fn main() {
1818- let ($0_0 , _1) = &(S,2);
1819- let s = _0 .f();
1811+ let ($0s , _1) = &(S,2);
1812+ let s = s .f();
18201813}
18211814 "# ,
18221815 )
@@ -1845,8 +1838,8 @@ impl S {
18451838}
18461839
18471840fn main() {
1848- let ($0_0 , _1) = &(S,2);
1849- let s = (*_0 ).f();
1841+ let ($0s , _1) = &(S,2);
1842+ let s = (*s ).f();
18501843}
18511844 "# ,
18521845 )
@@ -1882,8 +1875,8 @@ impl T for &S {
18821875}
18831876
18841877fn main() {
1885- let ($0_0 , _1) = &(S,2);
1886- let s = (*_0 ).f();
1878+ let ($0s , _1) = &(S,2);
1879+ let s = (*s ).f();
18871880}
18881881 "# ,
18891882 )
@@ -1923,8 +1916,8 @@ impl T for &S {
19231916}
19241917
19251918fn main() {
1926- let ($0_0 , _1) = &(S,2);
1927- let s = (*_0 ).f();
1919+ let ($0s , _1) = &(S,2);
1920+ let s = (*s ).f();
19281921}
19291922 "# ,
19301923 )
@@ -1951,8 +1944,8 @@ impl S {
19511944 fn do_stuff(&self) -> i32 { 42 }
19521945}
19531946fn main() {
1954- let ($0_0, _1 ) = &(S,&S);
1955- let v = _0 .do_stuff();
1947+ let ($0s, s1 ) = &(S,&S);
1948+ let v = s .do_stuff();
19561949}
19571950 "# ,
19581951 )
@@ -1973,7 +1966,7 @@ fn main() {
19731966 // `t.0` gets auto-refed -> no deref needed -> no parens
19741967 let v = t.0.do_stuff(); // no deref, no parens
19751968 let v = &t.0.do_stuff(); // `&` is for result -> no deref, no parens
1976- // deref: `_1 ` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
1969+ // deref: `s1 ` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
19771970 let v = t.1.do_stuff(); // deref, parens
19781971}
19791972 "# ,
@@ -1984,13 +1977,13 @@ impl S {
19841977 fn do_stuff(&self) -> i32 { 42 }
19851978}
19861979fn main() {
1987- let ($0_0, _1 ) = &(S,&S);
1988- let v = _0 .do_stuff(); // no deref, remove parens
1980+ let ($0s, s1 ) = &(S,&S);
1981+ let v = s .do_stuff(); // no deref, remove parens
19891982 // `t.0` gets auto-refed -> no deref needed -> no parens
1990- let v = _0 .do_stuff(); // no deref, no parens
1991- let v = &_0 .do_stuff(); // `&` is for result -> no deref, no parens
1992- // deref: `_1 ` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
1993- let v = (*_1 ).do_stuff(); // deref, parens
1983+ let v = s .do_stuff(); // no deref, no parens
1984+ let v = &s .do_stuff(); // `&` is for result -> no deref, no parens
1985+ // deref: `s1 ` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
1986+ let v = (*s1 ).do_stuff(); // deref, parens
19941987}
19951988 "# ,
19961989 )
0 commit comments