@@ -36,11 +36,13 @@ use ide_db::{path_transform::PathTransform, traits::get_missing_assoc_items, Sym
36
36
use syntax:: {
37
37
ast:: { self , edit_in_place:: AttrsOwnerEdit } ,
38
38
display:: function_declaration,
39
- AstNode , SyntaxElement , SyntaxKind , SyntaxNode , SyntaxToken , TextRange , T ,
39
+ AstNode , SyntaxElement , SyntaxKind , SyntaxNode , TextRange , T ,
40
40
} ;
41
41
use text_edit:: TextEdit ;
42
42
43
- use crate :: { CompletionContext , CompletionItem , CompletionItemKind , Completions } ;
43
+ use crate :: {
44
+ CompletionContext , CompletionItem , CompletionItemKind , CompletionRelevance , Completions ,
45
+ } ;
44
46
45
47
#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
46
48
enum ImplCompletionKind {
@@ -51,30 +53,40 @@ enum ImplCompletionKind {
51
53
}
52
54
53
55
pub ( crate ) fn complete_trait_impl ( acc : & mut Completions , ctx : & CompletionContext ) {
54
- if let Some ( ( kind, trigger , impl_def) ) = completion_match ( ctx. token . clone ( ) ) {
56
+ if let Some ( ( kind, replacement_range , impl_def) ) = completion_match ( ctx) {
55
57
if let Some ( hir_impl) = ctx. sema . to_def ( & impl_def) {
56
58
get_missing_assoc_items ( & ctx. sema , & impl_def) . into_iter ( ) . for_each ( |item| {
57
59
match ( item, kind) {
58
60
(
59
61
hir:: AssocItem :: Function ( fn_item) ,
60
62
ImplCompletionKind :: All | ImplCompletionKind :: Fn ,
61
- ) => add_function_impl ( acc, ctx, & trigger , fn_item, hir_impl) ,
63
+ ) => add_function_impl ( acc, ctx, replacement_range , fn_item, hir_impl) ,
62
64
(
63
65
hir:: AssocItem :: TypeAlias ( type_item) ,
64
66
ImplCompletionKind :: All | ImplCompletionKind :: TypeAlias ,
65
- ) => add_type_alias_impl ( acc, ctx, & trigger , type_item) ,
67
+ ) => add_type_alias_impl ( acc, ctx, replacement_range , type_item) ,
66
68
(
67
69
hir:: AssocItem :: Const ( const_item) ,
68
70
ImplCompletionKind :: All | ImplCompletionKind :: Const ,
69
- ) => add_const_impl ( acc, ctx, & trigger , const_item, hir_impl) ,
71
+ ) => add_const_impl ( acc, ctx, replacement_range , const_item, hir_impl) ,
70
72
_ => { }
71
73
}
72
74
} ) ;
73
75
}
74
76
}
75
77
}
76
78
77
- fn completion_match ( mut token : SyntaxToken ) -> Option < ( ImplCompletionKind , SyntaxNode , ast:: Impl ) > {
79
+ fn completion_match ( ctx : & CompletionContext ) -> Option < ( ImplCompletionKind , TextRange , ast:: Impl ) > {
80
+ let mut token = ctx. token . clone ( ) ;
81
+
82
+ let parent_kind = token. parent ( ) . map_or ( SyntaxKind :: EOF , |it| it. kind ( ) ) ;
83
+ if parent_kind == SyntaxKind :: ASSOC_ITEM_LIST {
84
+ let impl_def = ast:: Impl :: cast ( token. parent ( ) ?. parent ( ) ?) ?;
85
+ let kind = ImplCompletionKind :: All ;
86
+ let replacement_range = TextRange :: empty ( ctx. position . offset ) ;
87
+ return Some ( ( kind, replacement_range, impl_def) ) ;
88
+ }
89
+
78
90
// For keyword without name like `impl .. { fn $0 }`, the current position is inside
79
91
// the whitespace token, which is outside `FN` syntax node.
80
92
// We need to follow the previous token in this case.
@@ -122,13 +134,16 @@ fn completion_match(mut token: SyntaxToken) -> Option<(ImplCompletionKind, Synta
122
134
SyntaxKind :: MACRO_CALL => ImplCompletionKind :: All ,
123
135
_ => return None ,
124
136
} ;
125
- Some ( ( kind, impl_item, impl_def) )
137
+
138
+ let replacement_range = replacement_range ( ctx, & impl_item) ;
139
+
140
+ Some ( ( kind, replacement_range, impl_def) )
126
141
}
127
142
128
143
fn add_function_impl (
129
144
acc : & mut Completions ,
130
145
ctx : & CompletionContext ,
131
- fn_def_node : & SyntaxNode ,
146
+ replacement_range : TextRange ,
132
147
func : hir:: Function ,
133
148
impl_def : hir:: Impl ,
134
149
) {
@@ -146,9 +161,10 @@ fn add_function_impl(
146
161
CompletionItemKind :: SymbolKind ( SymbolKind :: Function )
147
162
} ;
148
163
149
- let range = replacement_range ( ctx, fn_def_node) ;
150
- let mut item = CompletionItem :: new ( completion_kind, range, label) ;
151
- item. lookup_by ( fn_name) . set_documentation ( func. docs ( ctx. db ) ) ;
164
+ let mut item = CompletionItem :: new ( completion_kind, replacement_range, label) ;
165
+ item. lookup_by ( fn_name)
166
+ . set_documentation ( func. docs ( ctx. db ) )
167
+ . set_relevance ( CompletionRelevance { is_item_from_trait : true , ..Default :: default ( ) } ) ;
152
168
153
169
if let Some ( source) = ctx. sema . source ( func) {
154
170
let assoc_item = ast:: AssocItem :: Fn ( source. value ) ;
@@ -162,11 +178,11 @@ fn add_function_impl(
162
178
match ctx. config . snippet_cap {
163
179
Some ( cap) => {
164
180
let snippet = format ! ( "{} {{\n $0\n }}" , function_decl) ;
165
- item. snippet_edit ( cap, TextEdit :: replace ( range , snippet) ) ;
181
+ item. snippet_edit ( cap, TextEdit :: replace ( replacement_range , snippet) ) ;
166
182
}
167
183
None => {
168
184
let header = format ! ( "{} {{" , function_decl) ;
169
- item. text_edit ( TextEdit :: replace ( range , header) ) ;
185
+ item. text_edit ( TextEdit :: replace ( replacement_range , header) ) ;
170
186
}
171
187
} ;
172
188
item. add_to ( acc) ;
@@ -201,25 +217,25 @@ fn get_transformed_assoc_item(
201
217
fn add_type_alias_impl (
202
218
acc : & mut Completions ,
203
219
ctx : & CompletionContext ,
204
- type_def_node : & SyntaxNode ,
220
+ replacement_range : TextRange ,
205
221
type_alias : hir:: TypeAlias ,
206
222
) {
207
223
let alias_name = type_alias. name ( ctx. db ) . to_smol_str ( ) ;
208
224
209
225
let snippet = format ! ( "type {} = " , alias_name) ;
210
226
211
- let range = replacement_range ( ctx, type_def_node) ;
212
- let mut item = CompletionItem :: new ( SymbolKind :: TypeAlias , range, & snippet) ;
213
- item. text_edit ( TextEdit :: replace ( range, snippet) )
227
+ let mut item = CompletionItem :: new ( SymbolKind :: TypeAlias , replacement_range, & snippet) ;
228
+ item. text_edit ( TextEdit :: replace ( replacement_range, snippet) )
214
229
. lookup_by ( alias_name)
215
- . set_documentation ( type_alias. docs ( ctx. db ) ) ;
230
+ . set_documentation ( type_alias. docs ( ctx. db ) )
231
+ . set_relevance ( CompletionRelevance { is_item_from_trait : true , ..Default :: default ( ) } ) ;
216
232
item. add_to ( acc) ;
217
233
}
218
234
219
235
fn add_const_impl (
220
236
acc : & mut Completions ,
221
237
ctx : & CompletionContext ,
222
- const_def_node : & SyntaxNode ,
238
+ replacement_range : TextRange ,
223
239
const_ : hir:: Const ,
224
240
impl_def : hir:: Impl ,
225
241
) {
@@ -236,11 +252,14 @@ fn add_const_impl(
236
252
237
253
let snippet = make_const_compl_syntax ( & transformed_const) ;
238
254
239
- let range = replacement_range ( ctx, const_def_node) ;
240
- let mut item = CompletionItem :: new ( SymbolKind :: Const , range, & snippet) ;
241
- item. text_edit ( TextEdit :: replace ( range, snippet) )
255
+ let mut item = CompletionItem :: new ( SymbolKind :: Const , replacement_range, & snippet) ;
256
+ item. text_edit ( TextEdit :: replace ( replacement_range, snippet) )
242
257
. lookup_by ( const_name)
243
- . set_documentation ( const_. docs ( ctx. db ) ) ;
258
+ . set_documentation ( const_. docs ( ctx. db ) )
259
+ . set_relevance ( CompletionRelevance {
260
+ is_item_from_trait : true ,
261
+ ..Default :: default ( )
262
+ } ) ;
244
263
item. add_to ( acc) ;
245
264
}
246
265
}
@@ -987,4 +1006,24 @@ where Self: SomeTrait<u32> {
987
1006
"# ,
988
1007
)
989
1008
}
1009
+
1010
+ #[ test]
1011
+ fn works_directly_in_impl ( ) {
1012
+ check (
1013
+ r#"
1014
+ trait Tr {
1015
+ fn provided() {}
1016
+ fn required();
1017
+ }
1018
+
1019
+ impl Tr for () {
1020
+ fn provided() {}
1021
+ $0
1022
+ }
1023
+ "# ,
1024
+ expect ! [ [ r#"
1025
+ fn fn required()
1026
+ "# ] ] ,
1027
+ ) ;
1028
+ }
990
1029
}
0 commit comments