1
- use ide_db:: text_edit:: TextRange ;
2
1
use ide_db:: {
3
2
assists:: { AssistId , AssistKind } ,
4
3
defs:: Definition ,
5
- search:: { FileReference , SearchScope , UsageSearchResult } ,
4
+ search:: { FileReference , SearchScope } ,
5
+ syntax_helpers:: suggest_name,
6
+ text_edit:: TextRange ,
6
7
} ;
7
8
use itertools:: Itertools ;
9
+ use syntax:: SmolStr ;
8
10
use syntax:: {
9
11
ast:: { self , make, AstNode , FieldExpr , HasName , IdentPat } ,
10
12
ted,
@@ -122,33 +124,43 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleDat
122
124
return None ;
123
125
}
124
126
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| {
128
128
Definition :: Local ( def)
129
129
. usages ( & ctx. sema )
130
130
. in_scope ( & SearchScope :: single_file ( ctx. file_id ( ) ) )
131
131
. all ( )
132
+ . iter ( )
133
+ . next ( )
134
+ . map ( |( _, refs) | refs. to_vec ( ) )
132
135
} ) ;
133
136
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
+ } )
136
159
. collect :: < Vec < _ > > ( ) ;
137
160
138
161
Some ( TupleData { ident_pat, ref_type, field_names, usages } )
139
162
}
140
163
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
-
152
164
enum RefType {
153
165
ReadOnly ,
154
166
Mutable ,
@@ -157,7 +169,7 @@ struct TupleData {
157
169
ident_pat : IdentPat ,
158
170
ref_type : Option < RefType > ,
159
171
field_names : Vec < String > ,
160
- usages : Option < UsageSearchResult > ,
172
+ usages : Option < Vec < FileReference > > ,
161
173
}
162
174
fn edit_tuple_assignment (
163
175
ctx : & AssistContext < ' _ > ,
@@ -213,42 +225,23 @@ fn edit_tuple_usages(
213
225
ctx : & AssistContext < ' _ > ,
214
226
in_sub_pattern : bool ,
215
227
) -> 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)
252
245
}
253
246
fn edit_tuple_usage (
254
247
ctx : & AssistContext < ' _ > ,
@@ -1769,14 +1762,14 @@ struct S4 {
1769
1762
}
1770
1763
1771
1764
fn 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);
1773
1766
let v: i32 = *_0; // deref, no parens
1774
1767
let v: &i32 = _0; // no deref, no parens, remove `&`
1775
1768
f1(*_0); // deref, no parens
1776
1769
f2(_0); // `&*` -> cancel out -> no deref, no parens
1777
1770
// https://github.com/rust-lang/rust-analyzer/issues/1109#issuecomment-658868639
1778
1771
// 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
1780
1773
(*_0).do_stuff(); // deref, parens
1781
1774
let v: i32 = (*_2)?; // deref, parens
1782
1775
let v: i32 = _3[0]; // no deref, no parens
@@ -1815,8 +1808,8 @@ impl S {
1815
1808
}
1816
1809
1817
1810
fn main() {
1818
- let ($0_0 , _1) = &(S,2);
1819
- let s = _0 .f();
1811
+ let ($0s , _1) = &(S,2);
1812
+ let s = s .f();
1820
1813
}
1821
1814
"# ,
1822
1815
)
@@ -1845,8 +1838,8 @@ impl S {
1845
1838
}
1846
1839
1847
1840
fn main() {
1848
- let ($0_0 , _1) = &(S,2);
1849
- let s = (*_0 ).f();
1841
+ let ($0s , _1) = &(S,2);
1842
+ let s = (*s ).f();
1850
1843
}
1851
1844
"# ,
1852
1845
)
@@ -1882,8 +1875,8 @@ impl T for &S {
1882
1875
}
1883
1876
1884
1877
fn main() {
1885
- let ($0_0 , _1) = &(S,2);
1886
- let s = (*_0 ).f();
1878
+ let ($0s , _1) = &(S,2);
1879
+ let s = (*s ).f();
1887
1880
}
1888
1881
"# ,
1889
1882
)
@@ -1923,8 +1916,8 @@ impl T for &S {
1923
1916
}
1924
1917
1925
1918
fn main() {
1926
- let ($0_0 , _1) = &(S,2);
1927
- let s = (*_0 ).f();
1919
+ let ($0s , _1) = &(S,2);
1920
+ let s = (*s ).f();
1928
1921
}
1929
1922
"# ,
1930
1923
)
@@ -1951,8 +1944,8 @@ impl S {
1951
1944
fn do_stuff(&self) -> i32 { 42 }
1952
1945
}
1953
1946
fn 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();
1956
1949
}
1957
1950
"# ,
1958
1951
)
@@ -1973,7 +1966,7 @@ fn main() {
1973
1966
// `t.0` gets auto-refed -> no deref needed -> no parens
1974
1967
let v = t.0.do_stuff(); // no deref, no parens
1975
1968
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`
1977
1970
let v = t.1.do_stuff(); // deref, parens
1978
1971
}
1979
1972
"# ,
@@ -1984,13 +1977,13 @@ impl S {
1984
1977
fn do_stuff(&self) -> i32 { 42 }
1985
1978
}
1986
1979
fn 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
1989
1982
// `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
1994
1987
}
1995
1988
"# ,
1996
1989
)
0 commit comments