@@ -16,7 +16,7 @@ use stdx::format_to;
1616use syntax:: {
1717 algo,
1818 ast:: { self , HasArgList } ,
19- match_ast, AstNode , Direction , SyntaxToken , TextRange , TextSize ,
19+ match_ast, AstNode , Direction , SyntaxElementChildren , SyntaxToken , TextRange , TextSize ,
2020} ;
2121
2222use crate :: RootDatabase ;
@@ -102,6 +102,20 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio
102102 }
103103 return signature_help_for_record_lit( & sema, record, token) ;
104104 } ,
105+ ast:: RecordPat ( record) => {
106+ let cursor_outside = record. record_pat_field_list( ) . and_then( |list| list. r_curly_token( ) ) . as_ref( ) == Some ( & token) ;
107+ if cursor_outside {
108+ continue ;
109+ }
110+ return signature_help_for_record_pat( & sema, record, token) ;
111+ } ,
112+ ast:: TupleStructPat ( tuple_pat) => {
113+ let cursor_outside = tuple_pat. r_paren_token( ) . as_ref( ) == Some ( & token) ;
114+ if cursor_outside {
115+ continue ;
116+ }
117+ return signature_help_for_tuple_struct_pat( & sema, tuple_pat, token) ;
118+ } ,
105119 _ => ( ) ,
106120 }
107121 }
@@ -346,10 +360,111 @@ fn signature_help_for_record_lit(
346360 record : ast:: RecordExpr ,
347361 token : SyntaxToken ,
348362) -> Option < SignatureHelp > {
349- let active_parameter = record
350- . record_expr_field_list ( ) ?
363+ signature_help_for_record_ (
364+ sema,
365+ record. record_expr_field_list ( ) ?. syntax ( ) . children_with_tokens ( ) ,
366+ & record. path ( ) ?,
367+ record
368+ . record_expr_field_list ( ) ?
369+ . fields ( )
370+ . filter_map ( |field| sema. resolve_record_field ( & field) )
371+ . map ( |( field, _, ty) | ( field, ty) ) ,
372+ token,
373+ )
374+ }
375+
376+ fn signature_help_for_record_pat (
377+ sema : & Semantics < ' _ , RootDatabase > ,
378+ record : ast:: RecordPat ,
379+ token : SyntaxToken ,
380+ ) -> Option < SignatureHelp > {
381+ signature_help_for_record_ (
382+ sema,
383+ record. record_pat_field_list ( ) ?. syntax ( ) . children_with_tokens ( ) ,
384+ & record. path ( ) ?,
385+ record
386+ . record_pat_field_list ( ) ?
387+ . fields ( )
388+ . filter_map ( |field| sema. resolve_record_pat_field ( & field) ) ,
389+ token,
390+ )
391+ }
392+
393+ fn signature_help_for_tuple_struct_pat (
394+ sema : & Semantics < ' _ , RootDatabase > ,
395+ pat : ast:: TupleStructPat ,
396+ token : SyntaxToken ,
397+ ) -> Option < SignatureHelp > {
398+ let rest_pat = pat. fields ( ) . find ( |it| matches ! ( it, ast:: Pat :: RestPat ( _) ) ) ;
399+ let is_left_of_rest_pat =
400+ rest_pat. map_or ( true , |it| token. text_range ( ) . start ( ) < it. syntax ( ) . text_range ( ) . end ( ) ) ;
401+
402+ let mut res = SignatureHelp {
403+ doc : None ,
404+ signature : String :: new ( ) ,
405+ parameters : vec ! [ ] ,
406+ active_parameter : None ,
407+ } ;
408+
409+ let db = sema. db ;
410+ let path_res = sema. resolve_path ( & pat. path ( ) ?) ?;
411+ let fields: Vec < _ > = if let PathResolution :: Def ( ModuleDef :: Variant ( variant) ) = path_res {
412+ let en = variant. parent_enum ( db) ;
413+
414+ res. doc = en. docs ( db) . map ( |it| it. into ( ) ) ;
415+ format_to ! ( res. signature, "enum {}::{} (" , en. name( db) , variant. name( db) ) ;
416+ variant. fields ( db)
417+ } else {
418+ let adt = match path_res {
419+ PathResolution :: SelfType ( imp) => imp. self_ty ( db) . as_adt ( ) ?,
420+ PathResolution :: Def ( ModuleDef :: Adt ( adt) ) => adt,
421+ _ => return None ,
422+ } ;
423+
424+ match adt {
425+ hir:: Adt :: Struct ( it) => {
426+ res. doc = it. docs ( db) . map ( |it| it. into ( ) ) ;
427+ format_to ! ( res. signature, "struct {} (" , it. name( db) ) ;
428+ it. fields ( db)
429+ }
430+ _ => return None ,
431+ }
432+ } ;
433+ let commas = pat
351434 . syntax ( )
352435 . children_with_tokens ( )
436+ . filter_map ( syntax:: NodeOrToken :: into_token)
437+ . filter ( |t| t. kind ( ) == syntax:: T ![ , ] ) ;
438+ res. active_parameter = Some ( if is_left_of_rest_pat {
439+ commas. take_while ( |t| t. text_range ( ) . start ( ) <= token. text_range ( ) . start ( ) ) . count ( )
440+ } else {
441+ let n_commas = commas
442+ . collect :: < Vec < _ > > ( )
443+ . into_iter ( )
444+ . rev ( )
445+ . take_while ( |t| t. text_range ( ) . start ( ) > token. text_range ( ) . start ( ) )
446+ . count ( ) ;
447+ fields. len ( ) . saturating_sub ( 1 ) . saturating_sub ( n_commas)
448+ } ) ;
449+
450+ let mut buf = String :: new ( ) ;
451+ for ty in fields. into_iter ( ) . map ( |it| it. ty ( db) ) {
452+ format_to ! ( buf, "{}" , ty. display_truncated( db, Some ( 20 ) ) ) ;
453+ res. push_call_param ( & buf) ;
454+ buf. clear ( ) ;
455+ }
456+ res. signature . push_str ( ")" ) ;
457+ Some ( res)
458+ }
459+
460+ fn signature_help_for_record_ (
461+ sema : & Semantics < ' _ , RootDatabase > ,
462+ field_list_children : SyntaxElementChildren ,
463+ path : & ast:: Path ,
464+ fields2 : impl Iterator < Item = ( hir:: Field , hir:: Type ) > ,
465+ token : SyntaxToken ,
466+ ) -> Option < SignatureHelp > {
467+ let active_parameter = field_list_children
353468 . filter_map ( syntax:: NodeOrToken :: into_token)
354469 . filter ( |t| t. kind ( ) == syntax:: T ![ , ] )
355470 . take_while ( |t| t. text_range ( ) . start ( ) <= token. text_range ( ) . start ( ) )
@@ -365,7 +480,7 @@ fn signature_help_for_record_lit(
365480 let fields;
366481
367482 let db = sema. db ;
368- let path_res = sema. resolve_path ( & record . path ( ) ? ) ?;
483+ let path_res = sema. resolve_path ( path) ?;
369484 if let PathResolution :: Def ( ModuleDef :: Variant ( variant) ) = path_res {
370485 fields = variant. fields ( db) ;
371486 let en = variant. parent_enum ( db) ;
@@ -397,8 +512,7 @@ fn signature_help_for_record_lit(
397512 let mut fields =
398513 fields. into_iter ( ) . map ( |field| ( field. name ( db) , Some ( field) ) ) . collect :: < FxIndexMap < _ , _ > > ( ) ;
399514 let mut buf = String :: new ( ) ;
400- for field in record. record_expr_field_list ( ) ?. fields ( ) {
401- let Some ( ( field, _, ty) ) = sema. resolve_record_field ( & field) else { continue } ;
515+ for ( field, ty) in fields2 {
402516 let name = field. name ( db) ;
403517 format_to ! ( buf, "{name}: {}" , ty. display_truncated( db, Some ( 20 ) ) ) ;
404518 res. push_record_field ( & buf) ;
@@ -439,6 +553,7 @@ mod tests {
439553 ( database, FilePosition { file_id, offset } )
440554 }
441555
556+ #[ track_caller]
442557 fn check ( ra_fixture : & str , expect : Expect ) {
443558 let fixture = format ! (
444559 r#"
@@ -890,6 +1005,119 @@ fn main() {
8901005 ) ;
8911006 }
8921007
1008+ #[ test]
1009+ fn tuple_struct_pat ( ) {
1010+ check (
1011+ r#"
1012+ /// A cool tuple struct
1013+ struct S(u32, i32);
1014+ fn main() {
1015+ let S(0, $0);
1016+ }
1017+ "# ,
1018+ expect ! [ [ r#"
1019+ A cool tuple struct
1020+ ------
1021+ struct S (u32, i32)
1022+ --- ^^^
1023+ "# ] ] ,
1024+ ) ;
1025+ }
1026+
1027+ #[ test]
1028+ fn tuple_struct_pat_rest ( ) {
1029+ check (
1030+ r#"
1031+ /// A cool tuple struct
1032+ struct S(u32, i32, f32, u16);
1033+ fn main() {
1034+ let S(0, .., $0);
1035+ }
1036+ "# ,
1037+ expect ! [ [ r#"
1038+ A cool tuple struct
1039+ ------
1040+ struct S (u32, i32, f32, u16)
1041+ --- --- --- ^^^
1042+ "# ] ] ,
1043+ ) ;
1044+ check (
1045+ r#"
1046+ /// A cool tuple struct
1047+ struct S(u32, i32, f32, u16, u8);
1048+ fn main() {
1049+ let S(0, .., $0, 0);
1050+ }
1051+ "# ,
1052+ expect ! [ [ r#"
1053+ A cool tuple struct
1054+ ------
1055+ struct S (u32, i32, f32, u16, u8)
1056+ --- --- --- ^^^ --
1057+ "# ] ] ,
1058+ ) ;
1059+ check (
1060+ r#"
1061+ /// A cool tuple struct
1062+ struct S(u32, i32, f32, u16);
1063+ fn main() {
1064+ let S($0, .., 1);
1065+ }
1066+ "# ,
1067+ expect ! [ [ r#"
1068+ A cool tuple struct
1069+ ------
1070+ struct S (u32, i32, f32, u16)
1071+ ^^^ --- --- ---
1072+ "# ] ] ,
1073+ ) ;
1074+ check (
1075+ r#"
1076+ /// A cool tuple struct
1077+ struct S(u32, i32, f32, u16, u8);
1078+ fn main() {
1079+ let S(1, .., 1, $0, 2);
1080+ }
1081+ "# ,
1082+ expect ! [ [ r#"
1083+ A cool tuple struct
1084+ ------
1085+ struct S (u32, i32, f32, u16, u8)
1086+ --- --- --- ^^^ --
1087+ "# ] ] ,
1088+ ) ;
1089+ check (
1090+ r#"
1091+ /// A cool tuple struct
1092+ struct S(u32, i32, f32, u16);
1093+ fn main() {
1094+ let S(1, $0.., 1);
1095+ }
1096+ "# ,
1097+ expect ! [ [ r#"
1098+ A cool tuple struct
1099+ ------
1100+ struct S (u32, i32, f32, u16)
1101+ --- ^^^ --- ---
1102+ "# ] ] ,
1103+ ) ;
1104+ check (
1105+ r#"
1106+ /// A cool tuple struct
1107+ struct S(u32, i32, f32, u16);
1108+ fn main() {
1109+ let S(1, ..$0, 1);
1110+ }
1111+ "# ,
1112+ expect ! [ [ r#"
1113+ A cool tuple struct
1114+ ------
1115+ struct S (u32, i32, f32, u16)
1116+ --- ^^^ --- ---
1117+ "# ] ] ,
1118+ ) ;
1119+ }
1120+
8931121 #[ test]
8941122 fn generic_struct ( ) {
8951123 check (
@@ -1550,6 +1778,29 @@ impl S {
15501778 ) ;
15511779 }
15521780
1781+ #[ test]
1782+ fn record_pat ( ) {
1783+ check (
1784+ r#"
1785+ struct Strukt<T, U = ()> {
1786+ t: T,
1787+ u: U,
1788+ unit: (),
1789+ }
1790+ fn f() {
1791+ let Strukt {
1792+ u: 0,
1793+ $0
1794+ }
1795+ }
1796+ "# ,
1797+ expect ! [ [ r#"
1798+ struct Strukt { u: i32, t: T, unit: () }
1799+ ------ ^^^^ --------
1800+ "# ] ] ,
1801+ ) ;
1802+ }
1803+
15531804 #[ test]
15541805 fn test_enum_in_nested_method_in_lambda ( ) {
15551806 check (
0 commit comments