@@ -46,76 +46,76 @@ use crate::{
4646 display:: function_declaration,
4747} ;
4848
49+ #[ derive( Debug , PartialEq , Eq ) ]
50+ enum ImplCompletionKind {
51+ All ,
52+ Fn ,
53+ TypeAlias ,
54+ Const ,
55+ }
56+
4957pub ( 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)
7664 }
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)
8869 }
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)
10074 }
101-
10275 _ => { }
103- }
76+ } ) ;
10477 }
10578}
10679
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 ) )
11196 }
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 ) ) ,
113112 _ => None ,
114113 } ) ?;
114+
115115 let impl_def = ( 0 ..impl_def_offset - 1 )
116116 . try_fold ( trigger. parent ( ) ?, |t, _| t. parent ( ) )
117117 . and_then ( ast:: Impl :: cast) ?;
118- Some ( ( trigger, impl_def) )
118+ Some ( ( kind , trigger, impl_def) )
119119}
120120
121121fn add_function_impl (
@@ -485,4 +485,67 @@ impl Test for () {
485485" ,
486486 ) ;
487487 }
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+ }
488551}
0 commit comments