diff options
-rw-r--r-- | crates/ide/src/completion/complete_trait_impl.rs | 248 |
1 files changed, 215 insertions, 33 deletions
diff --git a/crates/ide/src/completion/complete_trait_impl.rs b/crates/ide/src/completion/complete_trait_impl.rs index bff2603b8..ff115df92 100644 --- a/crates/ide/src/completion/complete_trait_impl.rs +++ b/crates/ide/src/completion/complete_trait_impl.rs | |||
@@ -86,36 +86,46 @@ fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, Synt | |||
86 | token = token.prev_token()?; | 86 | token = token.prev_token()?; |
87 | } | 87 | } |
88 | 88 | ||
89 | let (kind, trigger, impl_def_offset) = token.ancestors().find_map(|p| match p.kind() { | 89 | let impl_item_offset = match token.kind() { |
90 | // `const` can be a modifier of an item, so the `const` token may be inside another item syntax node. | 90 | // `impl .. { const <|> }` |
91 | // Eg. `impl .. { const <|> fn bar() .. }` | 91 | // ERROR 0 |
92 | SyntaxKind::FN | SyntaxKind::TYPE_ALIAS | SyntaxKind::CONST | 92 | // CONST_KW <- * |
93 | if token.kind() == SyntaxKind::CONST_KW => | 93 | SyntaxKind::CONST_KW => 0, |
94 | { | 94 | // `impl .. { fn/type <|> }` |
95 | Some((ImplCompletionKind::Const, p, 2)) | 95 | // FN/TYPE_ALIAS 0 |
96 | } | 96 | // FN_KW <- * |
97 | SyntaxKind::FN => Some((ImplCompletionKind::Fn, p, 2)), | 97 | SyntaxKind::FN_KW | SyntaxKind::TYPE_KW => 0, |
98 | SyntaxKind::TYPE_ALIAS => Some((ImplCompletionKind::TypeAlias, p, 2)), | 98 | // `impl .. { fn/type/const foo<|> }` |
99 | SyntaxKind::CONST => Some((ImplCompletionKind::Const, p, 2)), | 99 | // FN/TYPE_ALIAS/CONST 1 |
100 | // `impl .. { const <|> }` is parsed as: | 100 | // NAME 0 |
101 | // IMPL | 101 | // IDENT <- * |
102 | // ASSOC_ITEM_LIST | 102 | SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME => 1, |
103 | // ERROR | 103 | // `impl .. { foo<|> }` |
104 | // CONST_KW <- token | 104 | // MACRO_CALL 3 |
105 | // WHITESPACE <- ctx.token | 105 | // PATH 2 |
106 | SyntaxKind::ERROR | 106 | // PATH_SEGMENT 1 |
107 | if p.first_token().map_or(false, |t| t.kind() == SyntaxKind::CONST_KW) => | 107 | // NAME_REF 0 |
108 | { | 108 | // IDENT <- * |
109 | Some((ImplCompletionKind::Const, p, 2)) | 109 | SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME_REF => 3, |
110 | } | 110 | _ => return None, |
111 | SyntaxKind::NAME_REF => Some((ImplCompletionKind::All, p, 5)), | 111 | }; |
112 | _ => None, | ||
113 | })?; | ||
114 | 112 | ||
115 | let impl_def = (0..impl_def_offset - 1) | 113 | let impl_item = token.ancestors().nth(impl_item_offset)?; |
116 | .try_fold(trigger.parent()?, |t, _| t.parent()) | 114 | // Must directly belong to an impl block. |
117 | .and_then(ast::Impl::cast)?; | 115 | // IMPL |
118 | Some((kind, trigger, impl_def)) | 116 | // ASSOC_ITEM_LIST |
117 | // <item> | ||
118 | let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?; | ||
119 | let kind = match impl_item.kind() { | ||
120 | // `impl ... { const <|> fn/type/const }` | ||
121 | _ if token.kind() == SyntaxKind::CONST_KW => ImplCompletionKind::Const, | ||
122 | SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const, | ||
123 | SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias, | ||
124 | SyntaxKind::FN => ImplCompletionKind::Fn, | ||
125 | SyntaxKind::MACRO_CALL => ImplCompletionKind::All, | ||
126 | _ => return None, | ||
127 | }; | ||
128 | Some((kind, impl_item, impl_def)) | ||
119 | } | 129 | } |
120 | 130 | ||
121 | fn add_function_impl( | 131 | fn add_function_impl( |
@@ -261,19 +271,191 @@ ta type TestType = \n\ | |||
261 | } | 271 | } |
262 | 272 | ||
263 | #[test] | 273 | #[test] |
264 | fn no_nested_fn_completions() { | 274 | fn no_completion_inside_fn() { |
265 | check( | 275 | check( |
266 | r" | 276 | r" |
267 | trait Test { | 277 | trait Test { fn test(); fn test2(); } |
268 | fn test(); | 278 | struct T; |
269 | fn test2(); | 279 | |
280 | impl Test for T { | ||
281 | fn test() { | ||
282 | t<|> | ||
283 | } | ||
284 | } | ||
285 | ", | ||
286 | expect![[""]], | ||
287 | ); | ||
288 | |||
289 | check( | ||
290 | r" | ||
291 | trait Test { fn test(); fn test2(); } | ||
292 | struct T; | ||
293 | |||
294 | impl Test for T { | ||
295 | fn test() { | ||
296 | fn t<|> | ||
297 | } | ||
270 | } | 298 | } |
299 | ", | ||
300 | expect![[""]], | ||
301 | ); | ||
302 | |||
303 | check( | ||
304 | r" | ||
305 | trait Test { fn test(); fn test2(); } | ||
271 | struct T; | 306 | struct T; |
272 | 307 | ||
273 | impl Test for T { | 308 | impl Test for T { |
274 | fn test() { | 309 | fn test() { |
310 | fn <|> | ||
311 | } | ||
312 | } | ||
313 | ", | ||
314 | expect![[""]], | ||
315 | ); | ||
316 | |||
317 | // https://github.com/rust-analyzer/rust-analyzer/pull/5976#issuecomment-692332191 | ||
318 | check( | ||
319 | r" | ||
320 | trait Test { fn test(); fn test2(); } | ||
321 | struct T; | ||
322 | |||
323 | impl Test for T { | ||
324 | fn test() { | ||
325 | foo.<|> | ||
326 | } | ||
327 | } | ||
328 | ", | ||
329 | expect![[""]], | ||
330 | ); | ||
331 | |||
332 | check( | ||
333 | r" | ||
334 | trait Test { fn test(_: i32); fn test2(); } | ||
335 | struct T; | ||
336 | |||
337 | impl Test for T { | ||
338 | fn test(t<|>) | ||
339 | } | ||
340 | ", | ||
341 | expect![[""]], | ||
342 | ); | ||
343 | |||
344 | check( | ||
345 | r" | ||
346 | trait Test { fn test(_: fn()); fn test2(); } | ||
347 | struct T; | ||
348 | |||
349 | impl Test for T { | ||
350 | fn test(f: fn <|>) | ||
351 | } | ||
352 | ", | ||
353 | expect![[""]], | ||
354 | ); | ||
355 | } | ||
356 | |||
357 | #[test] | ||
358 | fn no_completion_inside_const() { | ||
359 | check( | ||
360 | r" | ||
361 | trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); } | ||
362 | struct T; | ||
363 | |||
364 | impl Test for T { | ||
365 | const TEST: fn <|> | ||
366 | } | ||
367 | ", | ||
368 | expect![[""]], | ||
369 | ); | ||
370 | |||
371 | check( | ||
372 | r" | ||
373 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
374 | struct T; | ||
375 | |||
376 | impl Test for T { | ||
377 | const TEST: T<|> | ||
378 | } | ||
379 | ", | ||
380 | expect![[""]], | ||
381 | ); | ||
382 | |||
383 | check( | ||
384 | r" | ||
385 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
386 | struct T; | ||
387 | |||
388 | impl Test for T { | ||
389 | const TEST: u32 = f<|> | ||
390 | } | ||
391 | ", | ||
392 | expect![[""]], | ||
393 | ); | ||
394 | |||
395 | check( | ||
396 | r" | ||
397 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
398 | struct T; | ||
399 | |||
400 | impl Test for T { | ||
401 | const TEST: u32 = { | ||
275 | t<|> | 402 | t<|> |
403 | }; | ||
404 | } | ||
405 | ", | ||
406 | expect![[""]], | ||
407 | ); | ||
408 | |||
409 | check( | ||
410 | r" | ||
411 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
412 | struct T; | ||
413 | |||
414 | impl Test for T { | ||
415 | const TEST: u32 = { | ||
416 | fn <|> | ||
417 | }; | ||
418 | } | ||
419 | ", | ||
420 | expect![[""]], | ||
421 | ); | ||
422 | |||
423 | check( | ||
424 | r" | ||
425 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
426 | struct T; | ||
427 | |||
428 | impl Test for T { | ||
429 | const TEST: u32 = { | ||
430 | fn t<|> | ||
431 | }; | ||
432 | } | ||
433 | ", | ||
434 | expect![[""]], | ||
435 | ); | ||
276 | } | 436 | } |
437 | |||
438 | #[test] | ||
439 | fn no_completion_inside_type() { | ||
440 | check( | ||
441 | r" | ||
442 | trait Test { type Test; type Test2; fn test(); } | ||
443 | struct T; | ||
444 | |||
445 | impl Test for T { | ||
446 | type Test = T<|>; | ||
447 | } | ||
448 | ", | ||
449 | expect![[""]], | ||
450 | ); | ||
451 | |||
452 | check( | ||
453 | r" | ||
454 | trait Test { type Test; type Test2; fn test(); } | ||
455 | struct T; | ||
456 | |||
457 | impl Test for T { | ||
458 | type Test = fn <|>; | ||
277 | } | 459 | } |
278 | ", | 460 | ", |
279 | expect![[""]], | 461 | expect![[""]], |