1 //! Completion for associated items in a trait implementation.
2 //!
3 //! This module adds the completion items related to implementing associated
4 //! items within an `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$0
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() {}$0
31 //! }
32 //! ```
33
34 use hir::{self, HasAttrs};
35 use ide_db::{
36 path_transform::PathTransform, syntax_helpers::insert_whitespace_into_node,
37 traits::get_missing_assoc_items, SymbolKind,
38 };
39 use syntax::{
40 ast::{self, edit_in_place::AttrsOwnerEdit, HasTypeBounds},
41 AstNode, SyntaxElement, SyntaxKind, TextRange, T,
42 };
43 use text_edit::TextEdit;
44
45 use crate::{
46 context::PathCompletionCtx, CompletionContext, CompletionItem, CompletionItemKind,
47 CompletionRelevance, Completions,
48 };
49
50 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
51 enum ImplCompletionKind {
52 All,
53 Fn,
54 TypeAlias,
55 Const,
56 }
57
complete_trait_impl_const( acc: &mut Completions, ctx: &CompletionContext<'_>, name: &Option<ast::Name>, ) -> Option<()>58 pub(crate) fn complete_trait_impl_const(
59 acc: &mut Completions,
60 ctx: &CompletionContext<'_>,
61 name: &Option<ast::Name>,
62 ) -> Option<()> {
63 complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::Const)
64 }
65
complete_trait_impl_type_alias( acc: &mut Completions, ctx: &CompletionContext<'_>, name: &Option<ast::Name>, ) -> Option<()>66 pub(crate) fn complete_trait_impl_type_alias(
67 acc: &mut Completions,
68 ctx: &CompletionContext<'_>,
69 name: &Option<ast::Name>,
70 ) -> Option<()> {
71 complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::TypeAlias)
72 }
73
complete_trait_impl_fn( acc: &mut Completions, ctx: &CompletionContext<'_>, name: &Option<ast::Name>, ) -> Option<()>74 pub(crate) fn complete_trait_impl_fn(
75 acc: &mut Completions,
76 ctx: &CompletionContext<'_>,
77 name: &Option<ast::Name>,
78 ) -> Option<()> {
79 complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::Fn)
80 }
81
complete_trait_impl_name( acc: &mut Completions, ctx: &CompletionContext<'_>, name: &Option<ast::Name>, kind: ImplCompletionKind, ) -> Option<()>82 fn complete_trait_impl_name(
83 acc: &mut Completions,
84 ctx: &CompletionContext<'_>,
85 name: &Option<ast::Name>,
86 kind: ImplCompletionKind,
87 ) -> Option<()> {
88 let item = match name {
89 Some(name) => name.syntax().parent(),
90 None => {
91 let token = &ctx.token;
92 match token.kind() {
93 SyntaxKind::WHITESPACE => token.prev_token()?,
94 _ => token.clone(),
95 }
96 .parent()
97 }
98 }?;
99 let item = ctx.sema.original_syntax_node(&item)?;
100 // item -> ASSOC_ITEM_LIST -> IMPL
101 let impl_def = ast::Impl::cast(item.parent()?.parent()?)?;
102 let replacement_range = {
103 // ctx.sema.original_ast_node(item)?;
104 let first_child = item
105 .children_with_tokens()
106 .find(|child| {
107 !matches!(
108 child.kind(),
109 SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR
110 )
111 })
112 .unwrap_or_else(|| SyntaxElement::Node(item.clone()));
113
114 TextRange::new(first_child.text_range().start(), ctx.source_range().end())
115 };
116
117 complete_trait_impl(acc, ctx, kind, replacement_range, &impl_def);
118 Some(())
119 }
120
complete_trait_impl_item_by_name( acc: &mut Completions, ctx: &CompletionContext<'_>, path_ctx: &PathCompletionCtx, name_ref: &Option<ast::NameRef>, impl_: &Option<ast::Impl>, )121 pub(crate) fn complete_trait_impl_item_by_name(
122 acc: &mut Completions,
123 ctx: &CompletionContext<'_>,
124 path_ctx: &PathCompletionCtx,
125 name_ref: &Option<ast::NameRef>,
126 impl_: &Option<ast::Impl>,
127 ) {
128 if !path_ctx.is_trivial_path() {
129 return;
130 }
131 if let Some(impl_) = impl_ {
132 complete_trait_impl(
133 acc,
134 ctx,
135 ImplCompletionKind::All,
136 match name_ref {
137 Some(name) => name.syntax().text_range(),
138 None => ctx.source_range(),
139 },
140 impl_,
141 );
142 }
143 }
144
complete_trait_impl( acc: &mut Completions, ctx: &CompletionContext<'_>, kind: ImplCompletionKind, replacement_range: TextRange, impl_def: &ast::Impl, )145 fn complete_trait_impl(
146 acc: &mut Completions,
147 ctx: &CompletionContext<'_>,
148 kind: ImplCompletionKind,
149 replacement_range: TextRange,
150 impl_def: &ast::Impl,
151 ) {
152 if let Some(hir_impl) = ctx.sema.to_def(impl_def) {
153 get_missing_assoc_items(&ctx.sema, impl_def)
154 .into_iter()
155 .filter(|item| ctx.check_stability(Some(&item.attrs(ctx.db))))
156 .for_each(|item| {
157 use self::ImplCompletionKind::*;
158 match (item, kind) {
159 (hir::AssocItem::Function(func), All | Fn) => {
160 add_function_impl(acc, ctx, replacement_range, func, hir_impl)
161 }
162 (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => {
163 add_type_alias_impl(acc, ctx, replacement_range, type_alias, hir_impl)
164 }
165 (hir::AssocItem::Const(const_), All | Const) => {
166 add_const_impl(acc, ctx, replacement_range, const_, hir_impl)
167 }
168 _ => {}
169 }
170 });
171 }
172 }
173
add_function_impl( acc: &mut Completions, ctx: &CompletionContext<'_>, replacement_range: TextRange, func: hir::Function, impl_def: hir::Impl, )174 fn add_function_impl(
175 acc: &mut Completions,
176 ctx: &CompletionContext<'_>,
177 replacement_range: TextRange,
178 func: hir::Function,
179 impl_def: hir::Impl,
180 ) {
181 let fn_name = func.name(ctx.db);
182
183 let label = format!(
184 "fn {}({})",
185 fn_name.display(ctx.db),
186 if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." }
187 );
188
189 let completion_kind = if func.has_self_param(ctx.db) {
190 CompletionItemKind::Method
191 } else {
192 CompletionItemKind::SymbolKind(SymbolKind::Function)
193 };
194
195 let mut item = CompletionItem::new(completion_kind, replacement_range, label);
196 item.lookup_by(format!("fn {}", fn_name.display(ctx.db)))
197 .set_documentation(func.docs(ctx.db))
198 .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
199
200 if let Some(source) = ctx.sema.source(func) {
201 let assoc_item = ast::AssocItem::Fn(source.value);
202 if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
203 let transformed_fn = match transformed_item {
204 ast::AssocItem::Fn(func) => func,
205 _ => unreachable!(),
206 };
207
208 let function_decl = function_declaration(&transformed_fn, source.file_id.is_macro());
209 match ctx.config.snippet_cap {
210 Some(cap) => {
211 let snippet = format!("{function_decl} {{\n $0\n}}");
212 item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet));
213 }
214 None => {
215 let header = format!("{function_decl} {{");
216 item.text_edit(TextEdit::replace(replacement_range, header));
217 }
218 };
219 item.add_to(acc, ctx.db);
220 }
221 }
222 }
223
224 /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
get_transformed_assoc_item( ctx: &CompletionContext<'_>, assoc_item: ast::AssocItem, impl_def: hir::Impl, ) -> Option<ast::AssocItem>225 fn get_transformed_assoc_item(
226 ctx: &CompletionContext<'_>,
227 assoc_item: ast::AssocItem,
228 impl_def: hir::Impl,
229 ) -> Option<ast::AssocItem> {
230 let trait_ = impl_def.trait_(ctx.db)?;
231 let source_scope = &ctx.sema.scope(assoc_item.syntax())?;
232 let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value)?;
233 let transform = PathTransform::trait_impl(
234 target_scope,
235 source_scope,
236 trait_,
237 ctx.sema.source(impl_def)?.value,
238 );
239
240 let assoc_item = assoc_item.clone_for_update();
241 // FIXME: Paths in nested macros are not handled well. See
242 // `macro_generated_assoc_item2` test.
243 transform.apply(assoc_item.syntax());
244 assoc_item.remove_attrs_and_docs();
245 Some(assoc_item)
246 }
247
add_type_alias_impl( acc: &mut Completions, ctx: &CompletionContext<'_>, replacement_range: TextRange, type_alias: hir::TypeAlias, impl_def: hir::Impl, )248 fn add_type_alias_impl(
249 acc: &mut Completions,
250 ctx: &CompletionContext<'_>,
251 replacement_range: TextRange,
252 type_alias: hir::TypeAlias,
253 impl_def: hir::Impl,
254 ) {
255 let alias_name = type_alias.name(ctx.db).unescaped().to_smol_str();
256
257 let label = format!("type {alias_name} =");
258
259 let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label);
260 item.lookup_by(format!("type {alias_name}"))
261 .set_documentation(type_alias.docs(ctx.db))
262 .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
263
264 if let Some(source) = ctx.sema.source(type_alias) {
265 let assoc_item = ast::AssocItem::TypeAlias(source.value);
266 if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
267 let transformed_ty = match transformed_item {
268 ast::AssocItem::TypeAlias(ty) => ty,
269 _ => unreachable!(),
270 };
271
272 let start = transformed_ty.syntax().text_range().start();
273
274 let end = if let Some(end) =
275 transformed_ty.colon_token().map(|tok| tok.text_range().start())
276 {
277 end
278 } else if let Some(end) = transformed_ty.eq_token().map(|tok| tok.text_range().start())
279 {
280 end
281 } else if let Some(end) =
282 transformed_ty.semicolon_token().map(|tok| tok.text_range().start())
283 {
284 end
285 } else {
286 return;
287 };
288
289 let len = end - start;
290 let mut decl = transformed_ty.syntax().text().slice(..len).to_string();
291 if !decl.ends_with(' ') {
292 decl.push(' ');
293 }
294 decl.push_str("= ");
295
296 match ctx.config.snippet_cap {
297 Some(cap) => {
298 let snippet = format!("{decl}$0;");
299 item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet));
300 }
301 None => {
302 item.text_edit(TextEdit::replace(replacement_range, decl));
303 }
304 };
305 item.add_to(acc, ctx.db);
306 }
307 }
308 }
309
add_const_impl( acc: &mut Completions, ctx: &CompletionContext<'_>, replacement_range: TextRange, const_: hir::Const, impl_def: hir::Impl, )310 fn add_const_impl(
311 acc: &mut Completions,
312 ctx: &CompletionContext<'_>,
313 replacement_range: TextRange,
314 const_: hir::Const,
315 impl_def: hir::Impl,
316 ) {
317 let const_name = const_.name(ctx.db).map(|n| n.to_smol_str());
318
319 if let Some(const_name) = const_name {
320 if let Some(source) = ctx.sema.source(const_) {
321 let assoc_item = ast::AssocItem::Const(source.value);
322 if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
323 let transformed_const = match transformed_item {
324 ast::AssocItem::Const(const_) => const_,
325 _ => unreachable!(),
326 };
327
328 let label = make_const_compl_syntax(&transformed_const, source.file_id.is_macro());
329 let replacement = format!("{label} ");
330
331 let mut item = CompletionItem::new(SymbolKind::Const, replacement_range, label);
332 item.lookup_by(format!("const {const_name}"))
333 .set_documentation(const_.docs(ctx.db))
334 .set_relevance(CompletionRelevance {
335 is_item_from_trait: true,
336 ..Default::default()
337 });
338 match ctx.config.snippet_cap {
339 Some(cap) => item.snippet_edit(
340 cap,
341 TextEdit::replace(replacement_range, format!("{replacement}$0;")),
342 ),
343 None => item.text_edit(TextEdit::replace(replacement_range, replacement)),
344 };
345 item.add_to(acc, ctx.db);
346 }
347 }
348 }
349 }
350
make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> String351 fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> String {
352 let const_ = if needs_whitespace {
353 insert_whitespace_into_node::insert_ws_into(const_.syntax().clone())
354 } else {
355 const_.syntax().clone()
356 };
357
358 let start = const_.text_range().start();
359 let const_end = const_.text_range().end();
360
361 let end = const_
362 .children_with_tokens()
363 .find(|s| s.kind() == T![;] || s.kind() == T![=])
364 .map_or(const_end, |f| f.text_range().start());
365
366 let len = end - start;
367 let range = TextRange::new(0.into(), len);
368
369 let syntax = const_.text().slice(range).to_string();
370
371 format!("{} =", syntax.trim_end())
372 }
373
function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String374 fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String {
375 let node = if needs_whitespace {
376 insert_whitespace_into_node::insert_ws_into(node.syntax().clone())
377 } else {
378 node.syntax().clone()
379 };
380
381 let start = node.text_range().start();
382 let end = node.text_range().end();
383
384 let end = node
385 .last_child_or_token()
386 .filter(|s| s.kind() == T![;] || s.kind() == SyntaxKind::BLOCK_EXPR)
387 .map_or(end, |f| f.text_range().start());
388
389 let len = end - start;
390 let syntax = node.text().slice(..len).to_string();
391
392 syntax.trim_end().to_owned()
393 }
394
395 #[cfg(test)]
396 mod tests {
397 use expect_test::{expect, Expect};
398
399 use crate::tests::{check_edit, completion_list_no_kw};
400
check(ra_fixture: &str, expect: Expect)401 fn check(ra_fixture: &str, expect: Expect) {
402 let actual = completion_list_no_kw(ra_fixture);
403 expect.assert_eq(&actual)
404 }
405
406 #[test]
no_completion_inside_fn()407 fn no_completion_inside_fn() {
408 check(
409 r"
410 trait Test { fn test(); fn test2(); }
411 struct T;
412
413 impl Test for T {
414 fn test() {
415 t$0
416 }
417 }
418 ",
419 expect![[r#"
420 sp Self
421 st T
422 tt Test
423 bt u32
424 "#]],
425 );
426
427 check(
428 r"
429 trait Test { fn test(); fn test2(); }
430 struct T;
431
432 impl Test for T {
433 fn test() {
434 fn t$0
435 }
436 }
437 ",
438 expect![[""]],
439 );
440
441 check(
442 r"
443 trait Test { fn test(); fn test2(); }
444 struct T;
445
446 impl Test for T {
447 fn test() {
448 fn $0
449 }
450 }
451 ",
452 expect![[""]],
453 );
454
455 // https://github.com/rust-lang/rust-analyzer/pull/5976#issuecomment-692332191
456 check(
457 r"
458 trait Test { fn test(); fn test2(); }
459 struct T;
460
461 impl Test for T {
462 fn test() {
463 foo.$0
464 }
465 }
466 ",
467 expect![[r#""#]],
468 );
469
470 check(
471 r"
472 trait Test { fn test(_: i32); fn test2(); }
473 struct T;
474
475 impl Test for T {
476 fn test(t$0)
477 }
478 ",
479 expect![[r#"
480 sp Self
481 st T
482 bn &mut self
483 bn &self
484 bn mut self
485 bn self
486 "#]],
487 );
488
489 check(
490 r"
491 trait Test { fn test(_: fn()); fn test2(); }
492 struct T;
493
494 impl Test for T {
495 fn test(f: fn $0)
496 }
497 ",
498 expect![[r#"
499 sp Self
500 st T
501 "#]],
502 );
503 }
504
505 #[test]
no_completion_inside_const()506 fn no_completion_inside_const() {
507 check(
508 r"
509 trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); }
510 struct T;
511
512 impl Test for T {
513 const TEST: fn $0
514 }
515 ",
516 expect![[r#""#]],
517 );
518
519 check(
520 r"
521 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
522 struct T;
523
524 impl Test for T {
525 const TEST: T$0
526 }
527 ",
528 expect![[r#"
529 sp Self
530 st T
531 tt Test
532 bt u32
533 "#]],
534 );
535
536 check(
537 r"
538 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
539 struct T;
540
541 impl Test for T {
542 const TEST: u32 = f$0
543 }
544 ",
545 expect![[r#"
546 sp Self
547 st T
548 tt Test
549 bt u32
550 "#]],
551 );
552
553 check(
554 r"
555 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
556 struct T;
557
558 impl Test for T {
559 const TEST: u32 = {
560 t$0
561 };
562 }
563 ",
564 expect![[r#"
565 sp Self
566 st T
567 tt Test
568 bt u32
569 "#]],
570 );
571
572 check(
573 r"
574 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
575 struct T;
576
577 impl Test for T {
578 const TEST: u32 = {
579 fn $0
580 };
581 }
582 ",
583 expect![[""]],
584 );
585
586 check(
587 r"
588 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
589 struct T;
590
591 impl Test for T {
592 const TEST: u32 = {
593 fn t$0
594 };
595 }
596 ",
597 expect![[""]],
598 );
599 }
600
601 #[test]
no_completion_inside_type()602 fn no_completion_inside_type() {
603 check(
604 r"
605 trait Test { type Test; type Test2; fn test(); }
606 struct T;
607
608 impl Test for T {
609 type Test = T$0;
610 }
611 ",
612 expect![[r#"
613 sp Self
614 st T
615 tt Test
616 bt u32
617 "#]],
618 );
619
620 check(
621 r"
622 trait Test { type Test; type Test2; fn test(); }
623 struct T;
624
625 impl Test for T {
626 type Test = fn $0;
627 }
628 ",
629 expect![[r#""#]],
630 );
631 }
632
633 #[test]
name_ref_single_function()634 fn name_ref_single_function() {
635 check_edit(
636 "fn test",
637 r#"
638 trait Test {
639 fn test();
640 }
641 struct T;
642
643 impl Test for T {
644 t$0
645 }
646 "#,
647 r#"
648 trait Test {
649 fn test();
650 }
651 struct T;
652
653 impl Test for T {
654 fn test() {
655 $0
656 }
657 }
658 "#,
659 );
660 }
661
662 #[test]
single_function()663 fn single_function() {
664 check_edit(
665 "fn test",
666 r#"
667 trait Test {
668 fn test();
669 }
670 struct T;
671
672 impl Test for T {
673 fn t$0
674 }
675 "#,
676 r#"
677 trait Test {
678 fn test();
679 }
680 struct T;
681
682 impl Test for T {
683 fn test() {
684 $0
685 }
686 }
687 "#,
688 );
689 }
690
691 #[test]
generic_fn()692 fn generic_fn() {
693 check_edit(
694 "fn foo",
695 r#"
696 trait Test {
697 fn foo<T>();
698 }
699 struct T;
700
701 impl Test for T {
702 fn f$0
703 }
704 "#,
705 r#"
706 trait Test {
707 fn foo<T>();
708 }
709 struct T;
710
711 impl Test for T {
712 fn foo<T>() {
713 $0
714 }
715 }
716 "#,
717 );
718 check_edit(
719 "fn foo",
720 r#"
721 trait Test {
722 fn foo<T>() where T: Into<String>;
723 }
724 struct T;
725
726 impl Test for T {
727 fn f$0
728 }
729 "#,
730 r#"
731 trait Test {
732 fn foo<T>() where T: Into<String>;
733 }
734 struct T;
735
736 impl Test for T {
737 fn foo<T>() where T: Into<String> {
738 $0
739 }
740 }
741 "#,
742 );
743 }
744
745 #[test]
associated_type()746 fn associated_type() {
747 check_edit(
748 "type SomeType",
749 r#"
750 trait Test {
751 type SomeType;
752 }
753
754 impl Test for () {
755 type S$0
756 }
757 "#,
758 "
759 trait Test {
760 type SomeType;
761 }
762
763 impl Test for () {
764 type SomeType = $0;\n\
765 }
766 ",
767 );
768 check_edit(
769 "type SomeType",
770 r#"
771 trait Test {
772 type SomeType;
773 }
774
775 impl Test for () {
776 type$0
777 }
778 "#,
779 "
780 trait Test {
781 type SomeType;
782 }
783
784 impl Test for () {
785 type SomeType = $0;\n\
786 }
787 ",
788 );
789 }
790
791 #[test]
associated_const()792 fn associated_const() {
793 check_edit(
794 "const SOME_CONST",
795 r#"
796 trait Test {
797 const SOME_CONST: u16;
798 }
799
800 impl Test for () {
801 const S$0
802 }
803 "#,
804 "
805 trait Test {
806 const SOME_CONST: u16;
807 }
808
809 impl Test for () {
810 const SOME_CONST: u16 = $0;\n\
811 }
812 ",
813 );
814
815 check_edit(
816 "const SOME_CONST",
817 r#"
818 trait Test {
819 const SOME_CONST: u16 = 92;
820 }
821
822 impl Test for () {
823 const S$0
824 }
825 "#,
826 "
827 trait Test {
828 const SOME_CONST: u16 = 92;
829 }
830
831 impl Test for () {
832 const SOME_CONST: u16 = $0;\n\
833 }
834 ",
835 );
836 }
837
838 #[test]
fn_with_lifetimes()839 fn fn_with_lifetimes() {
840 check_edit(
841 "fn foo",
842 r#"
843 trait Test<'a, 'b, T> {
844 fn foo(&self, a: &'a T, b: &'b T) -> &'a T;
845 }
846
847 impl<'x, 'y, A> Test<'x, 'y, A> for () {
848 t$0
849 }
850 "#,
851 r#"
852 trait Test<'a, 'b, T> {
853 fn foo(&self, a: &'a T, b: &'b T) -> &'a T;
854 }
855
856 impl<'x, 'y, A> Test<'x, 'y, A> for () {
857 fn foo(&self, a: &'x A, b: &'y A) -> &'x A {
858 $0
859 }
860 }
861 "#,
862 );
863 }
864
865 #[test]
complete_without_name()866 fn complete_without_name() {
867 let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| {
868 check_edit(
869 completion,
870 &format!(
871 r#"
872 trait Test {{
873 type Foo;
874 const CONST: u16;
875 fn bar();
876 }}
877 struct T;
878
879 impl Test for T {{
880 {hint}
881 {next_sibling}
882 }}
883 "#
884 ),
885 &format!(
886 r#"
887 trait Test {{
888 type Foo;
889 const CONST: u16;
890 fn bar();
891 }}
892 struct T;
893
894 impl Test for T {{
895 {completed}
896 {next_sibling}
897 }}
898 "#
899 ),
900 )
901 };
902
903 // Enumerate some possible next siblings.
904 for next_sibling in [
905 "",
906 "fn other_fn() {}", // `const $0 fn` -> `const fn`
907 "type OtherType = i32;",
908 "const OTHER_CONST: i32 = 0;",
909 "async fn other_fn() {}",
910 "unsafe fn other_fn() {}",
911 "default fn other_fn() {}",
912 "default type OtherType = i32;",
913 "default const OTHER_CONST: i32 = 0;",
914 ] {
915 test("fn bar", "fn $0", "fn bar() {\n $0\n}", next_sibling);
916 test("type Foo", "type $0", "type Foo = $0;", next_sibling);
917 test("const CONST", "const $0", "const CONST: u16 = $0;", next_sibling);
918 }
919 }
920
921 #[test]
snippet_does_not_overwrite_comment_or_attr()922 fn snippet_does_not_overwrite_comment_or_attr() {
923 let test = |completion: &str, hint: &str, completed: &str| {
924 check_edit(
925 completion,
926 &format!(
927 r#"
928 trait Foo {{
929 type Type;
930 fn function();
931 const CONST: i32 = 0;
932 }}
933 struct T;
934
935 impl Foo for T {{
936 // Comment
937 #[bar]
938 {hint}
939 }}
940 "#
941 ),
942 &format!(
943 r#"
944 trait Foo {{
945 type Type;
946 fn function();
947 const CONST: i32 = 0;
948 }}
949 struct T;
950
951 impl Foo for T {{
952 // Comment
953 #[bar]
954 {completed}
955 }}
956 "#
957 ),
958 )
959 };
960 test("fn function", "fn f$0", "fn function() {\n $0\n}");
961 test("type Type", "type T$0", "type Type = $0;");
962 test("const CONST", "const C$0", "const CONST: i32 = $0;");
963 }
964
965 #[test]
generics_are_inlined_in_return_type()966 fn generics_are_inlined_in_return_type() {
967 check_edit(
968 "fn function",
969 r#"
970 trait Foo<T> {
971 fn function() -> T;
972 }
973 struct Bar;
974
975 impl Foo<u32> for Bar {
976 fn f$0
977 }
978 "#,
979 r#"
980 trait Foo<T> {
981 fn function() -> T;
982 }
983 struct Bar;
984
985 impl Foo<u32> for Bar {
986 fn function() -> u32 {
987 $0
988 }
989 }
990 "#,
991 )
992 }
993
994 #[test]
generics_are_inlined_in_parameter()995 fn generics_are_inlined_in_parameter() {
996 check_edit(
997 "fn function",
998 r#"
999 trait Foo<T> {
1000 fn function(bar: T);
1001 }
1002 struct Bar;
1003
1004 impl Foo<u32> for Bar {
1005 fn f$0
1006 }
1007 "#,
1008 r#"
1009 trait Foo<T> {
1010 fn function(bar: T);
1011 }
1012 struct Bar;
1013
1014 impl Foo<u32> for Bar {
1015 fn function(bar: u32) {
1016 $0
1017 }
1018 }
1019 "#,
1020 )
1021 }
1022
1023 #[test]
generics_are_inlined_when_part_of_other_types()1024 fn generics_are_inlined_when_part_of_other_types() {
1025 check_edit(
1026 "fn function",
1027 r#"
1028 trait Foo<T> {
1029 fn function(bar: Vec<T>);
1030 }
1031 struct Bar;
1032
1033 impl Foo<u32> for Bar {
1034 fn f$0
1035 }
1036 "#,
1037 r#"
1038 trait Foo<T> {
1039 fn function(bar: Vec<T>);
1040 }
1041 struct Bar;
1042
1043 impl Foo<u32> for Bar {
1044 fn function(bar: Vec<u32>) {
1045 $0
1046 }
1047 }
1048 "#,
1049 )
1050 }
1051
1052 #[test]
generics_are_inlined_complex()1053 fn generics_are_inlined_complex() {
1054 check_edit(
1055 "fn function",
1056 r#"
1057 trait Foo<T, U, V> {
1058 fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
1059 }
1060 struct Bar;
1061
1062 impl Foo<u32, Vec<usize>, u8> for Bar {
1063 fn f$0
1064 }
1065 "#,
1066 r#"
1067 trait Foo<T, U, V> {
1068 fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
1069 }
1070 struct Bar;
1071
1072 impl Foo<u32, Vec<usize>, u8> for Bar {
1073 fn function(bar: Vec<u32>, baz: Vec<usize>) -> Arc<Vec<u8>> {
1074 $0
1075 }
1076 }
1077 "#,
1078 )
1079 }
1080
1081 #[test]
generics_are_inlined_in_associated_const()1082 fn generics_are_inlined_in_associated_const() {
1083 check_edit(
1084 "const BAR",
1085 r#"
1086 trait Foo<T> {
1087 const BAR: T;
1088 }
1089 struct Bar;
1090
1091 impl Foo<u32> for Bar {
1092 const B$0
1093 }
1094 "#,
1095 r#"
1096 trait Foo<T> {
1097 const BAR: T;
1098 }
1099 struct Bar;
1100
1101 impl Foo<u32> for Bar {
1102 const BAR: u32 = $0;
1103 }
1104 "#,
1105 )
1106 }
1107
1108 #[test]
generics_are_inlined_in_where_clause()1109 fn generics_are_inlined_in_where_clause() {
1110 check_edit(
1111 "fn function",
1112 r#"
1113 trait SomeTrait<T> {}
1114
1115 trait Foo<T> {
1116 fn function()
1117 where Self: SomeTrait<T>;
1118 }
1119 struct Bar;
1120
1121 impl Foo<u32> for Bar {
1122 fn f$0
1123 }
1124 "#,
1125 r#"
1126 trait SomeTrait<T> {}
1127
1128 trait Foo<T> {
1129 fn function()
1130 where Self: SomeTrait<T>;
1131 }
1132 struct Bar;
1133
1134 impl Foo<u32> for Bar {
1135 fn function()
1136 where Self: SomeTrait<u32> {
1137 $0
1138 }
1139 }
1140 "#,
1141 )
1142 }
1143
1144 #[test]
works_directly_in_impl()1145 fn works_directly_in_impl() {
1146 check(
1147 r#"
1148 trait Tr {
1149 fn required();
1150 }
1151
1152 impl Tr for () {
1153 $0
1154 }
1155 "#,
1156 expect![[r#"
1157 fn fn required()
1158 "#]],
1159 );
1160 check(
1161 r#"
1162 trait Tr {
1163 fn provided() {}
1164 fn required();
1165 }
1166
1167 impl Tr for () {
1168 fn provided() {}
1169 $0
1170 }
1171 "#,
1172 expect![[r#"
1173 fn fn required()
1174 "#]],
1175 );
1176 }
1177
1178 #[test]
fixes_up_macro_generated()1179 fn fixes_up_macro_generated() {
1180 check_edit(
1181 "fn foo",
1182 r#"
1183 macro_rules! noop {
1184 ($($item: item)*) => {
1185 $($item)*
1186 }
1187 }
1188
1189 noop! {
1190 trait Foo {
1191 fn foo(&mut self, bar: i64, baz: &mut u32) -> Result<(), u32>;
1192 }
1193 }
1194
1195 struct Test;
1196
1197 impl Foo for Test {
1198 $0
1199 }
1200 "#,
1201 r#"
1202 macro_rules! noop {
1203 ($($item: item)*) => {
1204 $($item)*
1205 }
1206 }
1207
1208 noop! {
1209 trait Foo {
1210 fn foo(&mut self, bar: i64, baz: &mut u32) -> Result<(), u32>;
1211 }
1212 }
1213
1214 struct Test;
1215
1216 impl Foo for Test {
1217 fn foo(&mut self,bar:i64,baz: &mut u32) -> Result<(),u32> {
1218 $0
1219 }
1220 }
1221 "#,
1222 );
1223 }
1224
1225 #[test]
macro_generated_assoc_item()1226 fn macro_generated_assoc_item() {
1227 check_edit(
1228 "fn method",
1229 r#"
1230 macro_rules! ty { () => { i32 } }
1231 trait SomeTrait { type Output; }
1232 impl SomeTrait for i32 { type Output = i64; }
1233 macro_rules! define_method {
1234 () => {
1235 fn method(&mut self, params: <ty!() as SomeTrait>::Output);
1236 };
1237 }
1238 trait AnotherTrait { define_method!(); }
1239 impl AnotherTrait for () {
1240 $0
1241 }
1242 "#,
1243 r#"
1244 macro_rules! ty { () => { i32 } }
1245 trait SomeTrait { type Output; }
1246 impl SomeTrait for i32 { type Output = i64; }
1247 macro_rules! define_method {
1248 () => {
1249 fn method(&mut self, params: <ty!() as SomeTrait>::Output);
1250 };
1251 }
1252 trait AnotherTrait { define_method!(); }
1253 impl AnotherTrait for () {
1254 fn method(&mut self,params: <ty!()as SomeTrait>::Output) {
1255 $0
1256 }
1257 }
1258 "#,
1259 );
1260 }
1261
1262 // FIXME: `T` in `ty!(T)` should be replaced by `PathTransform`.
1263 #[test]
macro_generated_assoc_item2()1264 fn macro_generated_assoc_item2() {
1265 check_edit(
1266 "fn method",
1267 r#"
1268 macro_rules! ty { ($me:ty) => { $me } }
1269 trait SomeTrait { type Output; }
1270 impl SomeTrait for i32 { type Output = i64; }
1271 macro_rules! define_method {
1272 ($t:ty) => {
1273 fn method(&mut self, params: <ty!($t) as SomeTrait>::Output);
1274 };
1275 }
1276 trait AnotherTrait<T: SomeTrait> { define_method!(T); }
1277 impl AnotherTrait<i32> for () {
1278 $0
1279 }
1280 "#,
1281 r#"
1282 macro_rules! ty { ($me:ty) => { $me } }
1283 trait SomeTrait { type Output; }
1284 impl SomeTrait for i32 { type Output = i64; }
1285 macro_rules! define_method {
1286 ($t:ty) => {
1287 fn method(&mut self, params: <ty!($t) as SomeTrait>::Output);
1288 };
1289 }
1290 trait AnotherTrait<T: SomeTrait> { define_method!(T); }
1291 impl AnotherTrait<i32> for () {
1292 fn method(&mut self,params: <ty!(T)as SomeTrait>::Output) {
1293 $0
1294 }
1295 }
1296 "#,
1297 );
1298 }
1299
1300 #[test]
includes_gat_generics()1301 fn includes_gat_generics() {
1302 check_edit(
1303 "type Ty",
1304 r#"
1305 trait Tr<'b> {
1306 type Ty<'a: 'b, T: Copy, const C: usize>;
1307 }
1308
1309 impl<'b> Tr<'b> for () {
1310 $0
1311 }
1312 "#,
1313 r#"
1314 trait Tr<'b> {
1315 type Ty<'a: 'b, T: Copy, const C: usize>;
1316 }
1317
1318 impl<'b> Tr<'b> for () {
1319 type Ty<'a: 'b, T: Copy, const C: usize> = $0;
1320 }
1321 "#,
1322 );
1323 }
1324
1325 #[test]
strips_comments()1326 fn strips_comments() {
1327 check_edit(
1328 "fn func",
1329 r#"
1330 trait Tr {
1331 /// docs
1332 #[attr]
1333 fn func();
1334 }
1335 impl Tr for () {
1336 $0
1337 }
1338 "#,
1339 r#"
1340 trait Tr {
1341 /// docs
1342 #[attr]
1343 fn func();
1344 }
1345 impl Tr for () {
1346 fn func() {
1347 $0
1348 }
1349 }
1350 "#,
1351 );
1352 check_edit(
1353 "const C",
1354 r#"
1355 trait Tr {
1356 /// docs
1357 #[attr]
1358 const C: usize;
1359 }
1360 impl Tr for () {
1361 $0
1362 }
1363 "#,
1364 r#"
1365 trait Tr {
1366 /// docs
1367 #[attr]
1368 const C: usize;
1369 }
1370 impl Tr for () {
1371 const C: usize = $0;
1372 }
1373 "#,
1374 );
1375 check_edit(
1376 "type Item",
1377 r#"
1378 trait Tr {
1379 /// docs
1380 #[attr]
1381 type Item;
1382 }
1383 impl Tr for () {
1384 $0
1385 }
1386 "#,
1387 r#"
1388 trait Tr {
1389 /// docs
1390 #[attr]
1391 type Item;
1392 }
1393 impl Tr for () {
1394 type Item = $0;
1395 }
1396 "#,
1397 );
1398 }
1399 }
1400