@@ -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+
849896pub 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