• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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