Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 4704a96

Browse files
committed
feat: improve name generation in destructure_tuple_binding
1 parent 2338efa commit 4704a96

File tree

3 files changed

+49
-33
lines changed

3 files changed

+49
-33
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use hir::{FileRange, Semantics};
44
use ide_db::EditionedFileId;
55
use ide_db::{label::Label, FileId, RootDatabase};
6+
use syntax::Edition;
67
use syntax::{
78
algo::{self, find_node_at_offset, find_node_at_range},
89
AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxToken, TextRange,
@@ -94,6 +95,10 @@ impl<'a> AssistContext<'a> {
9495
self.frange.file_id
9596
}
9697

98+
pub(crate) fn edition(&self) -> Edition {
99+
self.frange.file_id.edition()
100+
}
101+
97102
pub(crate) fn has_empty_selection(&self) -> bool {
98103
self.trimmed_range.is_empty()
99104
}

src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
use ide_db::text_edit::TextRange;
21
use ide_db::{
32
assists::{AssistId, AssistKind},
43
defs::Definition,
54
search::{FileReference, SearchScope, UsageSearchResult},
5+
syntax_helpers::suggest_name,
6+
text_edit::TextRange,
67
};
78
use itertools::Itertools;
9+
use syntax::SmolStr;
810
use syntax::{
911
ast::{self, make, AstNode, FieldExpr, HasName, IdentPat},
1012
ted,
@@ -131,24 +133,31 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleDat
131133
.all()
132134
});
133135

134-
let field_names = (0..field_types.len())
135-
.map(|i| generate_name(ctx, i, &name, &ident_pat, &usages))
136+
let mut name_generator = {
137+
let mut names = vec![];
138+
ctx.sema.scope(ident_pat.syntax())?.process_all_names(&mut |name, scope| {
139+
if let hir::ScopeDef::Local(_) = scope {
140+
names.push(name.as_str().into())
141+
}
142+
});
143+
suggest_name::NameGenerator::new_with_names(names.iter().map(|s: &SmolStr| s.as_str()))
144+
};
145+
146+
let field_names = field_types
147+
.into_iter()
148+
.enumerate()
149+
.map(|(id, ty)| {
150+
match name_generator.for_type(&ty, ctx.db(), ctx.edition()) {
151+
Some(name) => name,
152+
None => name_generator.suggest_name(&format!("_{}", id)),
153+
}
154+
.to_string()
155+
})
136156
.collect::<Vec<_>>();
137157

138158
Some(TupleData { ident_pat, ref_type, field_names, usages })
139159
}
140160

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-
152161
enum RefType {
153162
ReadOnly,
154163
Mutable,
@@ -1769,14 +1778,14 @@ struct S4 {
17691778
}
17701779
17711780
fn foo() -> Option<()> {
1772-
let ($0_0, _1, _2, _3, _4, _5) = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
1781+
let ($0_0, _1, _2, _3, s4, _5) = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
17731782
let v: i32 = *_0; // deref, no parens
17741783
let v: &i32 = _0; // no deref, no parens, remove `&`
17751784
f1(*_0); // deref, no parens
17761785
f2(_0); // `&*` -> cancel out -> no deref, no parens
17771786
// https://github.com/rust-lang/rust-analyzer/issues/1109#issuecomment-658868639
17781787
// let v: i32 = t.1.0; // no deref, no parens
1779-
let v: i32 = _4.value; // no deref, no parens
1788+
let v: i32 = s4.value; // no deref, no parens
17801789
(*_0).do_stuff(); // deref, parens
17811790
let v: i32 = (*_2)?; // deref, parens
17821791
let v: i32 = _3[0]; // no deref, no parens
@@ -1815,8 +1824,8 @@ impl S {
18151824
}
18161825
18171826
fn main() {
1818-
let ($0_0, _1) = &(S,2);
1819-
let s = _0.f();
1827+
let ($0s, _1) = &(S,2);
1828+
let s = s.f();
18201829
}
18211830
"#,
18221831
)
@@ -1845,8 +1854,8 @@ impl S {
18451854
}
18461855
18471856
fn main() {
1848-
let ($0_0, _1) = &(S,2);
1849-
let s = (*_0).f();
1857+
let ($0s, _1) = &(S,2);
1858+
let s = (*s).f();
18501859
}
18511860
"#,
18521861
)
@@ -1882,8 +1891,8 @@ impl T for &S {
18821891
}
18831892
18841893
fn main() {
1885-
let ($0_0, _1) = &(S,2);
1886-
let s = (*_0).f();
1894+
let ($0s, _1) = &(S,2);
1895+
let s = (*s).f();
18871896
}
18881897
"#,
18891898
)
@@ -1923,8 +1932,8 @@ impl T for &S {
19231932
}
19241933
19251934
fn main() {
1926-
let ($0_0, _1) = &(S,2);
1927-
let s = (*_0).f();
1935+
let ($0s, _1) = &(S,2);
1936+
let s = (*s).f();
19281937
}
19291938
"#,
19301939
)
@@ -1951,8 +1960,8 @@ impl S {
19511960
fn do_stuff(&self) -> i32 { 42 }
19521961
}
19531962
fn main() {
1954-
let ($0_0, _1) = &(S,&S);
1955-
let v = _0.do_stuff();
1963+
let ($0s, s1) = &(S,&S);
1964+
let v = s.do_stuff();
19561965
}
19571966
"#,
19581967
)
@@ -1973,7 +1982,7 @@ fn main() {
19731982
// `t.0` gets auto-refed -> no deref needed -> no parens
19741983
let v = t.0.do_stuff(); // no deref, no parens
19751984
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`
1985+
// deref: `s1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
19771986
let v = t.1.do_stuff(); // deref, parens
19781987
}
19791988
"#,
@@ -1984,13 +1993,13 @@ impl S {
19841993
fn do_stuff(&self) -> i32 { 42 }
19851994
}
19861995
fn main() {
1987-
let ($0_0, _1) = &(S,&S);
1988-
let v = _0.do_stuff(); // no deref, remove parens
1996+
let ($0s, s1) = &(S,&S);
1997+
let v = s.do_stuff(); // no deref, remove parens
19891998
// `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
1999+
let v = s.do_stuff(); // no deref, no parens
2000+
let v = &s.do_stuff(); // `&` is for result -> no deref, no parens
2001+
// deref: `s1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
2002+
let v = (*s1).do_stuff(); // deref, parens
19942003
}
19952004
"#,
19962005
)

src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
377377
return None;
378378
}
379379
name
380+
} else if let Some(inner_ty) = ty.remove_ref() {
381+
return name_of_type(&inner_ty, db, edition);
380382
} else {
381383
return None;
382384
};

0 commit comments

Comments
 (0)