@@ -46,76 +46,76 @@ use crate::{
46
46
display:: function_declaration,
47
47
} ;
48
48
49
+ #[ derive( Debug , PartialEq , Eq ) ]
50
+ enum ImplCompletionKind {
51
+ All ,
52
+ Fn ,
53
+ TypeAlias ,
54
+ Const ,
55
+ }
56
+
49
57
pub ( crate ) fn complete_trait_impl ( acc : & mut Completions , ctx : & CompletionContext ) {
50
- if let Some ( ( trigger, impl_def) ) = completion_match ( ctx) {
51
- match trigger. kind ( ) {
52
- SyntaxKind :: NAME_REF => get_missing_assoc_items ( & ctx. sema , & impl_def)
53
- . into_iter ( )
54
- . for_each ( |item| match item {
55
- hir:: AssocItem :: Function ( fn_item) => {
56
- add_function_impl ( & trigger, acc, ctx, fn_item)
57
- }
58
- hir:: AssocItem :: TypeAlias ( type_item) => {
59
- add_type_alias_impl ( & trigger, acc, ctx, type_item)
60
- }
61
- hir:: AssocItem :: Const ( const_item) => {
62
- add_const_impl ( & trigger, acc, ctx, const_item)
63
- }
64
- } ) ,
65
-
66
- SyntaxKind :: FN => {
67
- for missing_fn in get_missing_assoc_items ( & ctx. sema , & impl_def)
68
- . into_iter ( )
69
- . filter_map ( |item| match item {
70
- hir:: AssocItem :: Function ( fn_item) => Some ( fn_item) ,
71
- _ => None ,
72
- } )
73
- {
74
- add_function_impl ( & trigger, acc, ctx, missing_fn) ;
75
- }
58
+ if let Some ( ( kind, trigger, impl_def) ) = completion_match ( ctx) {
59
+ get_missing_assoc_items ( & ctx. sema , & impl_def) . into_iter ( ) . for_each ( |item| match item {
60
+ hir:: AssocItem :: Function ( fn_item)
61
+ if kind == ImplCompletionKind :: All || kind == ImplCompletionKind :: Fn =>
62
+ {
63
+ add_function_impl ( & trigger, acc, ctx, fn_item)
76
64
}
77
-
78
- SyntaxKind :: TYPE_ALIAS => {
79
- for missing_fn in get_missing_assoc_items ( & ctx. sema , & impl_def)
80
- . into_iter ( )
81
- . filter_map ( |item| match item {
82
- hir:: AssocItem :: TypeAlias ( type_item) => Some ( type_item) ,
83
- _ => None ,
84
- } )
85
- {
86
- add_type_alias_impl ( & trigger, acc, ctx, missing_fn) ;
87
- }
65
+ hir:: AssocItem :: TypeAlias ( type_item)
66
+ if kind == ImplCompletionKind :: All || kind == ImplCompletionKind :: TypeAlias =>
67
+ {
68
+ add_type_alias_impl ( & trigger, acc, ctx, type_item)
88
69
}
89
-
90
- SyntaxKind :: CONST => {
91
- for missing_fn in get_missing_assoc_items ( & ctx. sema , & impl_def)
92
- . into_iter ( )
93
- . filter_map ( |item| match item {
94
- hir:: AssocItem :: Const ( const_item) => Some ( const_item) ,
95
- _ => None ,
96
- } )
97
- {
98
- add_const_impl ( & trigger, acc, ctx, missing_fn) ;
99
- }
70
+ hir:: AssocItem :: Const ( const_item)
71
+ if kind == ImplCompletionKind :: All || kind == ImplCompletionKind :: Const =>
72
+ {
73
+ add_const_impl ( & trigger, acc, ctx, const_item)
100
74
}
101
-
102
75
_ => { }
103
- }
76
+ } ) ;
104
77
}
105
78
}
106
79
107
- fn completion_match ( ctx : & CompletionContext ) -> Option < ( SyntaxNode , Impl ) > {
108
- let ( trigger, impl_def_offset) = ctx. token . ancestors ( ) . find_map ( |p| match p. kind ( ) {
109
- SyntaxKind :: FN | SyntaxKind :: TYPE_ALIAS | SyntaxKind :: CONST | SyntaxKind :: BLOCK_EXPR => {
110
- Some ( ( p, 2 ) )
80
+ fn completion_match ( ctx : & CompletionContext ) -> Option < ( ImplCompletionKind , SyntaxNode , Impl ) > {
81
+ let mut token = ctx. token . clone ( ) ;
82
+ // For keywork without name like `impl .. { fn <|> }`, the current position is inside
83
+ // the whitespace token, which is outside `FN` syntax node.
84
+ // We need to follow the previous token in this case.
85
+ if token. kind ( ) == SyntaxKind :: WHITESPACE {
86
+ token = token. prev_token ( ) ?;
87
+ }
88
+
89
+ let ( kind, trigger, impl_def_offset) = token. ancestors ( ) . find_map ( |p| match p. kind ( ) {
90
+ // `const` can be a modifier of an item, so the `const` token may be inside another item syntax node.
91
+ // Eg. `impl .. { const <|> fn bar() .. }`
92
+ SyntaxKind :: FN | SyntaxKind :: TYPE_ALIAS | SyntaxKind :: CONST
93
+ if token. kind ( ) == SyntaxKind :: CONST_KW =>
94
+ {
95
+ Some ( ( ImplCompletionKind :: Const , p, 2 ) )
111
96
}
112
- SyntaxKind :: NAME_REF => Some ( ( p, 5 ) ) ,
97
+ SyntaxKind :: FN => Some ( ( ImplCompletionKind :: Fn , p, 2 ) ) ,
98
+ SyntaxKind :: TYPE_ALIAS => Some ( ( ImplCompletionKind :: TypeAlias , p, 2 ) ) ,
99
+ SyntaxKind :: CONST => Some ( ( ImplCompletionKind :: Const , p, 2 ) ) ,
100
+ // `impl .. { const <|> }` is parsed as:
101
+ // IMPL
102
+ // ASSOC_ITEM_LIST
103
+ // ERROR
104
+ // CONST_KW <- token
105
+ // WHITESPACE <- ctx.token
106
+ SyntaxKind :: ERROR
107
+ if p. first_token ( ) . map_or ( false , |t| t. kind ( ) == SyntaxKind :: CONST_KW ) =>
108
+ {
109
+ Some ( ( ImplCompletionKind :: Const , p, 2 ) )
110
+ }
111
+ SyntaxKind :: NAME_REF => Some ( ( ImplCompletionKind :: All , p, 5 ) ) ,
113
112
_ => None ,
114
113
} ) ?;
114
+
115
115
let impl_def = ( 0 ..impl_def_offset - 1 )
116
116
. try_fold ( trigger. parent ( ) ?, |t, _| t. parent ( ) )
117
117
. and_then ( ast:: Impl :: cast) ?;
118
- Some ( ( trigger, impl_def) )
118
+ Some ( ( kind , trigger, impl_def) )
119
119
}
120
120
121
121
fn add_function_impl (
@@ -485,4 +485,67 @@ impl Test for () {
485
485
" ,
486
486
) ;
487
487
}
488
+
489
+ #[ test]
490
+ fn complete_without_name ( ) {
491
+ let test = |completion : & str , hint : & str , completed : & str , next_sibling : & str | {
492
+ println ! (
493
+ "completion='{}', hint='{}', next_sibling='{}'" ,
494
+ completion, hint, next_sibling
495
+ ) ;
496
+
497
+ check_edit (
498
+ completion,
499
+ & format ! (
500
+ r#"
501
+ trait Test {{
502
+ type Foo;
503
+ const CONST: u16;
504
+ fn bar();
505
+ }}
506
+ struct T;
507
+
508
+ impl Test for T {{
509
+ {}
510
+ {}
511
+ }}
512
+ "# ,
513
+ hint, next_sibling
514
+ ) ,
515
+ & format ! (
516
+ r#"
517
+ trait Test {{
518
+ type Foo;
519
+ const CONST: u16;
520
+ fn bar();
521
+ }}
522
+ struct T;
523
+
524
+ impl Test for T {{
525
+ {}
526
+ {}
527
+ }}
528
+ "# ,
529
+ completed, next_sibling
530
+ ) ,
531
+ )
532
+ } ;
533
+
534
+ // Enumerate some possible next siblings.
535
+ for next_sibling in & [
536
+ "" ,
537
+ "fn other_fn() {}" , // `const <|> fn` -> `const fn`
538
+ "type OtherType = i32;" ,
539
+ "const OTHER_CONST: i32 = 0;" ,
540
+ "async fn other_fn() {}" ,
541
+ "unsafe fn other_fn() {}" ,
542
+ "default fn other_fn() {}" ,
543
+ "default type OtherType = i32;" ,
544
+ "default const OTHER_CONST: i32 = 0;" ,
545
+ ] {
546
+ test ( "bar" , "fn <|>" , "fn bar() {\n $0\n }" , next_sibling) ;
547
+ test ( "Foo" , "type <|>" , "type Foo = " , next_sibling) ;
548
+ test ( "CONST" , "const <|>" , "const CONST: u16 = " , next_sibling) ;
549
+ }
550
+ }
488
551
}
0 commit comments