diff options
Diffstat (limited to 'crates/ide/src/completion/complete_trait_impl.rs')
-rw-r--r-- | crates/ide/src/completion/complete_trait_impl.rs | 733 |
1 files changed, 0 insertions, 733 deletions
diff --git a/crates/ide/src/completion/complete_trait_impl.rs b/crates/ide/src/completion/complete_trait_impl.rs deleted file mode 100644 index ff115df92..000000000 --- a/crates/ide/src/completion/complete_trait_impl.rs +++ /dev/null | |||
@@ -1,733 +0,0 @@ | |||
1 | //! Completion for associated items in a trait implementation. | ||
2 | //! | ||
3 | //! This module adds the completion items related to implementing associated | ||
4 | //! items within a `impl Trait for Struct` block. The current context node | ||
5 | //! must be within either a `FN`, `TYPE_ALIAS`, or `CONST` node | ||
6 | //! and an direct child of an `IMPL`. | ||
7 | //! | ||
8 | //! # Examples | ||
9 | //! | ||
10 | //! Considering the following trait `impl`: | ||
11 | //! | ||
12 | //! ```ignore | ||
13 | //! trait SomeTrait { | ||
14 | //! fn foo(); | ||
15 | //! } | ||
16 | //! | ||
17 | //! impl SomeTrait for () { | ||
18 | //! fn f<|> | ||
19 | //! } | ||
20 | //! ``` | ||
21 | //! | ||
22 | //! may result in the completion of the following method: | ||
23 | //! | ||
24 | //! ```ignore | ||
25 | //! # trait SomeTrait { | ||
26 | //! # fn foo(); | ||
27 | //! # } | ||
28 | //! | ||
29 | //! impl SomeTrait for () { | ||
30 | //! fn foo() {}<|> | ||
31 | //! } | ||
32 | //! ``` | ||
33 | |||
34 | use assists::utils::get_missing_assoc_items; | ||
35 | use hir::{self, HasAttrs, HasSource}; | ||
36 | use syntax::{ | ||
37 | ast::{self, edit, Impl}, | ||
38 | AstNode, SyntaxKind, SyntaxNode, TextRange, T, | ||
39 | }; | ||
40 | use text_edit::TextEdit; | ||
41 | |||
42 | use crate::{ | ||
43 | completion::{ | ||
44 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, | ||
45 | }, | ||
46 | display::function_declaration, | ||
47 | }; | ||
48 | |||
49 | #[derive(Debug, PartialEq, Eq)] | ||
50 | enum ImplCompletionKind { | ||
51 | All, | ||
52 | Fn, | ||
53 | TypeAlias, | ||
54 | Const, | ||
55 | } | ||
56 | |||
57 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | ||
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) | ||
64 | } | ||
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) | ||
69 | } | ||
70 | hir::AssocItem::Const(const_item) | ||
71 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => | ||
72 | { | ||
73 | add_const_impl(&trigger, acc, ctx, const_item) | ||
74 | } | ||
75 | _ => {} | ||
76 | }); | ||
77 | } | ||
78 | } | ||
79 | |||
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 impl_item_offset = match token.kind() { | ||
90 | // `impl .. { const <|> }` | ||
91 | // ERROR 0 | ||
92 | // CONST_KW <- * | ||
93 | SyntaxKind::CONST_KW => 0, | ||
94 | // `impl .. { fn/type <|> }` | ||
95 | // FN/TYPE_ALIAS 0 | ||
96 | // FN_KW <- * | ||
97 | SyntaxKind::FN_KW | SyntaxKind::TYPE_KW => 0, | ||
98 | // `impl .. { fn/type/const foo<|> }` | ||
99 | // FN/TYPE_ALIAS/CONST 1 | ||
100 | // NAME 0 | ||
101 | // IDENT <- * | ||
102 | SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME => 1, | ||
103 | // `impl .. { foo<|> }` | ||
104 | // MACRO_CALL 3 | ||
105 | // PATH 2 | ||
106 | // PATH_SEGMENT 1 | ||
107 | // NAME_REF 0 | ||
108 | // IDENT <- * | ||
109 | SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME_REF => 3, | ||
110 | _ => return None, | ||
111 | }; | ||
112 | |||
113 | let impl_item = token.ancestors().nth(impl_item_offset)?; | ||
114 | // Must directly belong to an impl block. | ||
115 | // IMPL | ||
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)) | ||
129 | } | ||
130 | |||
131 | fn add_function_impl( | ||
132 | fn_def_node: &SyntaxNode, | ||
133 | acc: &mut Completions, | ||
134 | ctx: &CompletionContext, | ||
135 | func: hir::Function, | ||
136 | ) { | ||
137 | let fn_name = func.name(ctx.db).to_string(); | ||
138 | |||
139 | let label = if func.params(ctx.db).is_empty() { | ||
140 | format!("fn {}()", fn_name) | ||
141 | } else { | ||
142 | format!("fn {}(..)", fn_name) | ||
143 | }; | ||
144 | |||
145 | let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) | ||
146 | .lookup_by(fn_name) | ||
147 | .set_documentation(func.docs(ctx.db)); | ||
148 | |||
149 | let completion_kind = if func.self_param(ctx.db).is_some() { | ||
150 | CompletionItemKind::Method | ||
151 | } else { | ||
152 | CompletionItemKind::Function | ||
153 | }; | ||
154 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); | ||
155 | |||
156 | let function_decl = function_declaration(&func.source(ctx.db).value); | ||
157 | match ctx.config.snippet_cap { | ||
158 | Some(cap) => { | ||
159 | let snippet = format!("{} {{\n $0\n}}", function_decl); | ||
160 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) | ||
161 | } | ||
162 | None => { | ||
163 | let header = format!("{} {{", function_decl); | ||
164 | builder.text_edit(TextEdit::replace(range, header)) | ||
165 | } | ||
166 | } | ||
167 | .kind(completion_kind) | ||
168 | .add_to(acc); | ||
169 | } | ||
170 | |||
171 | fn add_type_alias_impl( | ||
172 | type_def_node: &SyntaxNode, | ||
173 | acc: &mut Completions, | ||
174 | ctx: &CompletionContext, | ||
175 | type_alias: hir::TypeAlias, | ||
176 | ) { | ||
177 | let alias_name = type_alias.name(ctx.db).to_string(); | ||
178 | |||
179 | let snippet = format!("type {} = ", alias_name); | ||
180 | |||
181 | let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end()); | ||
182 | |||
183 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) | ||
184 | .text_edit(TextEdit::replace(range, snippet)) | ||
185 | .lookup_by(alias_name) | ||
186 | .kind(CompletionItemKind::TypeAlias) | ||
187 | .set_documentation(type_alias.docs(ctx.db)) | ||
188 | .add_to(acc); | ||
189 | } | ||
190 | |||
191 | fn add_const_impl( | ||
192 | const_def_node: &SyntaxNode, | ||
193 | acc: &mut Completions, | ||
194 | ctx: &CompletionContext, | ||
195 | const_: hir::Const, | ||
196 | ) { | ||
197 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); | ||
198 | |||
199 | if let Some(const_name) = const_name { | ||
200 | let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); | ||
201 | |||
202 | let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); | ||
203 | |||
204 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) | ||
205 | .text_edit(TextEdit::replace(range, snippet)) | ||
206 | .lookup_by(const_name) | ||
207 | .kind(CompletionItemKind::Const) | ||
208 | .set_documentation(const_.docs(ctx.db)) | ||
209 | .add_to(acc); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | fn make_const_compl_syntax(const_: &ast::Const) -> String { | ||
214 | let const_ = edit::remove_attrs_and_docs(const_); | ||
215 | |||
216 | let const_start = const_.syntax().text_range().start(); | ||
217 | let const_end = const_.syntax().text_range().end(); | ||
218 | |||
219 | let start = | ||
220 | const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start()); | ||
221 | |||
222 | let end = const_ | ||
223 | .syntax() | ||
224 | .children_with_tokens() | ||
225 | .find(|s| s.kind() == T![;] || s.kind() == T![=]) | ||
226 | .map_or(const_end, |f| f.text_range().start()); | ||
227 | |||
228 | let len = end - start; | ||
229 | let range = TextRange::new(0.into(), len); | ||
230 | |||
231 | let syntax = const_.syntax().text().slice(range).to_string(); | ||
232 | |||
233 | format!("{} = ", syntax.trim_end()) | ||
234 | } | ||
235 | |||
236 | #[cfg(test)] | ||
237 | mod tests { | ||
238 | use expect_test::{expect, Expect}; | ||
239 | |||
240 | use crate::completion::{ | ||
241 | test_utils::{check_edit, completion_list}, | ||
242 | CompletionKind, | ||
243 | }; | ||
244 | |||
245 | fn check(ra_fixture: &str, expect: Expect) { | ||
246 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | ||
247 | expect.assert_eq(&actual) | ||
248 | } | ||
249 | |||
250 | #[test] | ||
251 | fn name_ref_function_type_const() { | ||
252 | check( | ||
253 | r#" | ||
254 | trait Test { | ||
255 | type TestType; | ||
256 | const TEST_CONST: u16; | ||
257 | fn test(); | ||
258 | } | ||
259 | struct T; | ||
260 | |||
261 | impl Test for T { | ||
262 | t<|> | ||
263 | } | ||
264 | "#, | ||
265 | expect![[" | ||
266 | ct const TEST_CONST: u16 = \n\ | ||
267 | fn fn test() | ||
268 | ta type TestType = \n\ | ||
269 | "]], | ||
270 | ); | ||
271 | } | ||
272 | |||
273 | #[test] | ||
274 | fn no_completion_inside_fn() { | ||
275 | check( | ||
276 | r" | ||
277 | trait Test { fn test(); fn test2(); } | ||
278 | struct T; | ||
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 | } | ||
298 | } | ||
299 | ", | ||
300 | expect![[""]], | ||
301 | ); | ||
302 | |||
303 | check( | ||
304 | r" | ||
305 | trait Test { fn test(); fn test2(); } | ||
306 | struct T; | ||
307 | |||
308 | impl Test for T { | ||
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 = { | ||
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 | ); | ||
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 <|>; | ||
459 | } | ||
460 | ", | ||
461 | expect![[""]], | ||
462 | ); | ||
463 | } | ||
464 | |||
465 | #[test] | ||
466 | fn name_ref_single_function() { | ||
467 | check_edit( | ||
468 | "test", | ||
469 | r#" | ||
470 | trait Test { | ||
471 | fn test(); | ||
472 | } | ||
473 | struct T; | ||
474 | |||
475 | impl Test for T { | ||
476 | t<|> | ||
477 | } | ||
478 | "#, | ||
479 | r#" | ||
480 | trait Test { | ||
481 | fn test(); | ||
482 | } | ||
483 | struct T; | ||
484 | |||
485 | impl Test for T { | ||
486 | fn test() { | ||
487 | $0 | ||
488 | } | ||
489 | } | ||
490 | "#, | ||
491 | ); | ||
492 | } | ||
493 | |||
494 | #[test] | ||
495 | fn single_function() { | ||
496 | check_edit( | ||
497 | "test", | ||
498 | r#" | ||
499 | trait Test { | ||
500 | fn test(); | ||
501 | } | ||
502 | struct T; | ||
503 | |||
504 | impl Test for T { | ||
505 | fn t<|> | ||
506 | } | ||
507 | "#, | ||
508 | r#" | ||
509 | trait Test { | ||
510 | fn test(); | ||
511 | } | ||
512 | struct T; | ||
513 | |||
514 | impl Test for T { | ||
515 | fn test() { | ||
516 | $0 | ||
517 | } | ||
518 | } | ||
519 | "#, | ||
520 | ); | ||
521 | } | ||
522 | |||
523 | #[test] | ||
524 | fn hide_implemented_fn() { | ||
525 | check( | ||
526 | r#" | ||
527 | trait Test { | ||
528 | fn foo(); | ||
529 | fn foo_bar(); | ||
530 | } | ||
531 | struct T; | ||
532 | |||
533 | impl Test for T { | ||
534 | fn foo() {} | ||
535 | fn f<|> | ||
536 | } | ||
537 | "#, | ||
538 | expect![[r#" | ||
539 | fn fn foo_bar() | ||
540 | "#]], | ||
541 | ); | ||
542 | } | ||
543 | |||
544 | #[test] | ||
545 | fn generic_fn() { | ||
546 | check_edit( | ||
547 | "foo", | ||
548 | r#" | ||
549 | trait Test { | ||
550 | fn foo<T>(); | ||
551 | } | ||
552 | struct T; | ||
553 | |||
554 | impl Test for T { | ||
555 | fn f<|> | ||
556 | } | ||
557 | "#, | ||
558 | r#" | ||
559 | trait Test { | ||
560 | fn foo<T>(); | ||
561 | } | ||
562 | struct T; | ||
563 | |||
564 | impl Test for T { | ||
565 | fn foo<T>() { | ||
566 | $0 | ||
567 | } | ||
568 | } | ||
569 | "#, | ||
570 | ); | ||
571 | check_edit( | ||
572 | "foo", | ||
573 | r#" | ||
574 | trait Test { | ||
575 | fn foo<T>() where T: Into<String>; | ||
576 | } | ||
577 | struct T; | ||
578 | |||
579 | impl Test for T { | ||
580 | fn f<|> | ||
581 | } | ||
582 | "#, | ||
583 | r#" | ||
584 | trait Test { | ||
585 | fn foo<T>() where T: Into<String>; | ||
586 | } | ||
587 | struct T; | ||
588 | |||
589 | impl Test for T { | ||
590 | fn foo<T>() | ||
591 | where T: Into<String> { | ||
592 | $0 | ||
593 | } | ||
594 | } | ||
595 | "#, | ||
596 | ); | ||
597 | } | ||
598 | |||
599 | #[test] | ||
600 | fn associated_type() { | ||
601 | check_edit( | ||
602 | "SomeType", | ||
603 | r#" | ||
604 | trait Test { | ||
605 | type SomeType; | ||
606 | } | ||
607 | |||
608 | impl Test for () { | ||
609 | type S<|> | ||
610 | } | ||
611 | "#, | ||
612 | " | ||
613 | trait Test { | ||
614 | type SomeType; | ||
615 | } | ||
616 | |||
617 | impl Test for () { | ||
618 | type SomeType = \n\ | ||
619 | } | ||
620 | ", | ||
621 | ); | ||
622 | } | ||
623 | |||
624 | #[test] | ||
625 | fn associated_const() { | ||
626 | check_edit( | ||
627 | "SOME_CONST", | ||
628 | r#" | ||
629 | trait Test { | ||
630 | const SOME_CONST: u16; | ||
631 | } | ||
632 | |||
633 | impl Test for () { | ||
634 | const S<|> | ||
635 | } | ||
636 | "#, | ||
637 | " | ||
638 | trait Test { | ||
639 | const SOME_CONST: u16; | ||
640 | } | ||
641 | |||
642 | impl Test for () { | ||
643 | const SOME_CONST: u16 = \n\ | ||
644 | } | ||
645 | ", | ||
646 | ); | ||
647 | |||
648 | check_edit( | ||
649 | "SOME_CONST", | ||
650 | r#" | ||
651 | trait Test { | ||
652 | const SOME_CONST: u16 = 92; | ||
653 | } | ||
654 | |||
655 | impl Test for () { | ||
656 | const S<|> | ||
657 | } | ||
658 | "#, | ||
659 | " | ||
660 | trait Test { | ||
661 | const SOME_CONST: u16 = 92; | ||
662 | } | ||
663 | |||
664 | impl Test for () { | ||
665 | const SOME_CONST: u16 = \n\ | ||
666 | } | ||
667 | ", | ||
668 | ); | ||
669 | } | ||
670 | |||
671 | #[test] | ||
672 | fn complete_without_name() { | ||
673 | let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| { | ||
674 | println!( | ||
675 | "completion='{}', hint='{}', next_sibling='{}'", | ||
676 | completion, hint, next_sibling | ||
677 | ); | ||
678 | |||
679 | check_edit( | ||
680 | completion, | ||
681 | &format!( | ||
682 | r#" | ||
683 | trait Test {{ | ||
684 | type Foo; | ||
685 | const CONST: u16; | ||
686 | fn bar(); | ||
687 | }} | ||
688 | struct T; | ||
689 | |||
690 | impl Test for T {{ | ||
691 | {} | ||
692 | {} | ||
693 | }} | ||
694 | "#, | ||
695 | hint, next_sibling | ||
696 | ), | ||
697 | &format!( | ||
698 | r#" | ||
699 | trait Test {{ | ||
700 | type Foo; | ||
701 | const CONST: u16; | ||
702 | fn bar(); | ||
703 | }} | ||
704 | struct T; | ||
705 | |||
706 | impl Test for T {{ | ||
707 | {} | ||
708 | {} | ||
709 | }} | ||
710 | "#, | ||
711 | completed, next_sibling | ||
712 | ), | ||
713 | ) | ||
714 | }; | ||
715 | |||
716 | // Enumerate some possible next siblings. | ||
717 | for next_sibling in &[ | ||
718 | "", | ||
719 | "fn other_fn() {}", // `const <|> fn` -> `const fn` | ||
720 | "type OtherType = i32;", | ||
721 | "const OTHER_CONST: i32 = 0;", | ||
722 | "async fn other_fn() {}", | ||
723 | "unsafe fn other_fn() {}", | ||
724 | "default fn other_fn() {}", | ||
725 | "default type OtherType = i32;", | ||
726 | "default const OTHER_CONST: i32 = 0;", | ||
727 | ] { | ||
728 | test("bar", "fn <|>", "fn bar() {\n $0\n}", next_sibling); | ||
729 | test("Foo", "type <|>", "type Foo = ", next_sibling); | ||
730 | test("CONST", "const <|>", "const CONST: u16 = ", next_sibling); | ||
731 | } | ||
732 | } | ||
733 | } | ||