Skip to content

Commit 787ca88

Browse files
committed
Add IdentPat::set_pat
Needed so that the `tuple_pat` node gets added to the syntax tree, which is required as we're using structured snippets.
1 parent 6f68cd3 commit 787ca88

File tree

2 files changed

+76
-9
lines changed

2 files changed

+76
-9
lines changed

crates/ide-assists/src/handlers/destructure_tuple_binding.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,7 @@ impl AssignmentEdit {
197197
fn apply(self) {
198198
// with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)`
199199
if self.in_sub_pattern {
200-
ted::insert_all_raw(
201-
ted::Position::after(self.ident_pat.syntax()),
202-
vec![
203-
make::tokens::single_space().into(),
204-
make::token(T![@]).into(),
205-
make::tokens::single_space().into(),
206-
self.tuple_pat.syntax().clone().into(),
207-
],
208-
)
200+
self.ident_pat.set_pat(Some(self.tuple_pat.into()))
209201
} else {
210202
ted::replace(self.ident_pat.syntax(), self.tuple_pat.syntax())
211203
}

crates/syntax/src/ast/edit_in_place.rs

+75
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,53 @@ fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
846846
Some(())
847847
}
848848

849+
impl ast::IdentPat {
850+
pub fn set_pat(&self, pat: Option<ast::Pat>) {
851+
match pat {
852+
None => {
853+
if let Some(at_token) = self.at_token() {
854+
// Remove `@ Pat`
855+
let start = at_token.clone().into();
856+
let end = self
857+
.pat()
858+
.map(|it| it.syntax().clone().into())
859+
.unwrap_or_else(|| at_token.into());
860+
861+
ted::remove_all(start..=end);
862+
863+
// Remove any trailing ws
864+
if let Some(last) =
865+
self.syntax().last_token().filter(|it| it.kind() == WHITESPACE)
866+
{
867+
last.detach();
868+
}
869+
}
870+
}
871+
Some(pat) => {
872+
if let Some(old_pat) = self.pat() {
873+
// Replace existing pattern
874+
ted::replace(old_pat.syntax(), pat.syntax())
875+
} else if let Some(at_token) = self.at_token() {
876+
// Have an `@` token but not a pattern yet
877+
ted::insert(ted::Position::after(at_token), pat.syntax());
878+
} else {
879+
// Don't have an `@`, should have a name
880+
let name = self.name().unwrap();
881+
882+
ted::insert_all(
883+
ted::Position::after(name.syntax()),
884+
vec![
885+
make::token(T![@]).into(),
886+
make::tokens::single_space().into(),
887+
pat.syntax().clone().into(),
888+
],
889+
)
890+
}
891+
}
892+
}
893+
}
894+
}
895+
849896
pub trait HasVisibilityEdit: ast::HasVisibility {
850897
fn set_visibility(&self, visbility: ast::Visibility) {
851898
match self.visibility() {
@@ -947,6 +994,34 @@ mod tests {
947994
);
948995
}
949996

997+
#[test]
998+
fn test_ident_pat_set_pat() {
999+
#[track_caller]
1000+
fn check(before: &str, expected: &str, pat: Option<ast::Pat>) {
1001+
let pat = pat.map(|it| it.clone_for_update());
1002+
1003+
let ident_pat = ast_mut_from_text::<ast::IdentPat>(&format!("fn f() {{ {before} }}"));
1004+
ident_pat.set_pat(pat);
1005+
1006+
let after = ast_mut_from_text::<ast::IdentPat>(&format!("fn f() {{ {expected} }}"));
1007+
assert_eq!(ident_pat.to_string(), after.to_string());
1008+
}
1009+
1010+
// replacing
1011+
check("let a @ _;", "let a @ ();", Some(make::tuple_pat([]).into()));
1012+
1013+
// note: no trailing semicolon is added for the below tests since it
1014+
// seems to be picked up by the ident pat during error recovery?
1015+
1016+
// adding
1017+
check("let a ", "let a @ ()", Some(make::tuple_pat([]).into()));
1018+
check("let a @ ", "let a @ ()", Some(make::tuple_pat([]).into()));
1019+
1020+
// removing
1021+
check("let a @ ()", "let a", None);
1022+
check("let a @ ", "let a", None);
1023+
}
1024+
9501025
#[test]
9511026
fn add_variant_to_empty_enum() {
9521027
let variant = make::variant(make::name("Bar"), None).clone_for_update();

0 commit comments

Comments
 (0)