@@ -16,7 +16,7 @@ use stdx::format_to;
16
16
use syntax:: {
17
17
algo,
18
18
ast:: { self , HasArgList } ,
19
- match_ast, AstNode , Direction , SyntaxToken , TextRange , TextSize ,
19
+ match_ast, AstNode , Direction , SyntaxElementChildren , SyntaxToken , TextRange , TextSize ,
20
20
} ;
21
21
22
22
use crate :: RootDatabase ;
@@ -102,6 +102,20 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio
102
102
}
103
103
return signature_help_for_record_lit( & sema, record, token) ;
104
104
} ,
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
+ } ,
105
119
_ => ( ) ,
106
120
}
107
121
}
@@ -346,10 +360,111 @@ fn signature_help_for_record_lit(
346
360
record : ast:: RecordExpr ,
347
361
token : SyntaxToken ,
348
362
) -> 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
351
434
. syntax ( )
352
435
. 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
353
468
. filter_map ( syntax:: NodeOrToken :: into_token)
354
469
. filter ( |t| t. kind ( ) == syntax:: T ![ , ] )
355
470
. take_while ( |t| t. text_range ( ) . start ( ) <= token. text_range ( ) . start ( ) )
@@ -365,7 +480,7 @@ fn signature_help_for_record_lit(
365
480
let fields;
366
481
367
482
let db = sema. db ;
368
- let path_res = sema. resolve_path ( & record . path ( ) ? ) ?;
483
+ let path_res = sema. resolve_path ( path) ?;
369
484
if let PathResolution :: Def ( ModuleDef :: Variant ( variant) ) = path_res {
370
485
fields = variant. fields ( db) ;
371
486
let en = variant. parent_enum ( db) ;
@@ -397,8 +512,7 @@ fn signature_help_for_record_lit(
397
512
let mut fields =
398
513
fields. into_iter ( ) . map ( |field| ( field. name ( db) , Some ( field) ) ) . collect :: < FxIndexMap < _ , _ > > ( ) ;
399
514
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 {
402
516
let name = field. name ( db) ;
403
517
format_to ! ( buf, "{name}: {}" , ty. display_truncated( db, Some ( 20 ) ) ) ;
404
518
res. push_record_field ( & buf) ;
@@ -439,6 +553,7 @@ mod tests {
439
553
( database, FilePosition { file_id, offset } )
440
554
}
441
555
556
+ #[ track_caller]
442
557
fn check ( ra_fixture : & str , expect : Expect ) {
443
558
let fixture = format ! (
444
559
r#"
@@ -890,6 +1005,119 @@ fn main() {
890
1005
) ;
891
1006
}
892
1007
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
+
893
1121
#[ test]
894
1122
fn generic_struct ( ) {
895
1123
check (
@@ -1550,6 +1778,29 @@ impl S {
1550
1778
) ;
1551
1779
}
1552
1780
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
+
1553
1804
#[ test]
1554
1805
fn test_enum_in_nested_method_in_lambda ( ) {
1555
1806
check (
0 commit comments