Skip to main content

ide_completion/completions/item_list/
trait_impl.rs

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
34use hir::{MacroCallId, Name, db::ExpandDatabase};
35use ide_db::text_edit::TextEdit;
36use ide_db::{
37    SymbolKind, documentation::HasDocs, path_transform::PathTransform,
38    syntax_helpers::prettify_macro_expansion, traits::get_missing_assoc_items,
39};
40use syntax::ast::HasGenericParams;
41use syntax::syntax_editor::{Position, SyntaxEditor};
42use syntax::{
43    AstNode, SmolStr, SyntaxElement, SyntaxKind, T, TextRange, ToSmolStr,
44    ast::{
45        self, HasGenericArgs, HasTypeBounds,
46        edit::{AstNodeEdit, AttrsOwnerEdit},
47    },
48    format_smolstr,
49};
50
51use crate::{
52    CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, Completions,
53    context::PathCompletionCtx,
54};
55
56#[derive(Copy, Clone, Debug, PartialEq, Eq)]
57enum ImplCompletionKind {
58    All,
59    Fn,
60    TypeAlias,
61    Const,
62}
63
64pub(crate) fn complete_trait_impl_const(
65    acc: &mut Completions,
66    ctx: &CompletionContext<'_, '_>,
67    name: &Option<ast::Name>,
68) -> Option<()> {
69    complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::Const)
70}
71
72pub(crate) fn complete_trait_impl_type_alias(
73    acc: &mut Completions,
74    ctx: &CompletionContext<'_, '_>,
75    name: &Option<ast::Name>,
76) -> Option<()> {
77    complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::TypeAlias)
78}
79
80pub(crate) fn complete_trait_impl_fn(
81    acc: &mut Completions,
82    ctx: &CompletionContext<'_, '_>,
83    name: &Option<ast::Name>,
84) -> Option<()> {
85    complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::Fn)
86}
87
88fn complete_trait_impl_name(
89    acc: &mut Completions,
90    ctx: &CompletionContext<'_, '_>,
91    name: &Option<ast::Name>,
92    kind: ImplCompletionKind,
93) -> Option<()> {
94    let macro_file_item = match name {
95        Some(name) => name.syntax().parent(),
96        None => {
97            let token = &ctx.token;
98            match token.kind() {
99                SyntaxKind::WHITESPACE => token.prev_token()?,
100                _ => token.clone(),
101            }
102            .parent()
103        }
104    }?;
105    let real_file_item = ctx.sema.original_syntax_node_rooted(&macro_file_item)?;
106    // item -> ASSOC_ITEM_LIST -> IMPL
107    let impl_def = ast::Impl::cast(macro_file_item.parent()?.parent()?)?;
108    let replacement_range = {
109        // ctx.sema.original_ast_node(item)?;
110        let first_child = real_file_item
111            .children_with_tokens()
112            .find(|child| {
113                !matches!(
114                    child.kind(),
115                    SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR
116                )
117            })
118            .unwrap_or_else(|| SyntaxElement::Node(real_file_item.clone()));
119
120        TextRange::new(first_child.text_range().start(), ctx.source_range().end())
121    };
122
123    complete_trait_impl(acc, ctx, kind, replacement_range, &impl_def);
124    Some(())
125}
126
127pub(crate) fn complete_trait_impl_item_by_name(
128    acc: &mut Completions,
129    ctx: &CompletionContext<'_, '_>,
130    path_ctx: &PathCompletionCtx<'_>,
131    name_ref: &Option<ast::NameRef>,
132    impl_: &Option<ast::Impl>,
133) {
134    if !path_ctx.is_trivial_path() {
135        return;
136    }
137    if let Some(impl_) = impl_ {
138        complete_trait_impl(
139            acc,
140            ctx,
141            ImplCompletionKind::All,
142            match name_ref
143                .as_ref()
144                .and_then(|name| ctx.sema.original_syntax_node_rooted(name.syntax()))
145            {
146                Some(name) => name.text_range(),
147                None => ctx.source_range(),
148            },
149            impl_,
150        );
151    }
152}
153
154fn complete_trait_impl(
155    acc: &mut Completions,
156    ctx: &CompletionContext<'_, '_>,
157    kind: ImplCompletionKind,
158    replacement_range: TextRange,
159    impl_def: &ast::Impl,
160) {
161    if let Some(hir_impl) = ctx.sema.to_def(impl_def) {
162        get_missing_assoc_items(&ctx.sema, impl_def)
163            .into_iter()
164            .filter(|item| ctx.check_stability_and_hidden(*item))
165            .for_each(|item| {
166                use self::ImplCompletionKind::*;
167                match (item, kind) {
168                    (hir::AssocItem::Function(func), All | Fn) => {
169                        add_function_impl(acc, ctx, replacement_range, func, hir_impl)
170                    }
171                    (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => {
172                        add_type_alias_impl(acc, ctx, replacement_range, type_alias, hir_impl)
173                    }
174                    (hir::AssocItem::Const(const_), All | Const) => {
175                        add_const_impl(acc, ctx, replacement_range, const_, hir_impl)
176                    }
177                    _ => {}
178                }
179            });
180    }
181}
182
183fn add_function_impl(
184    acc: &mut Completions,
185    ctx: &CompletionContext<'_, '_>,
186    replacement_range: TextRange,
187    func: hir::Function,
188    impl_def: hir::Impl,
189) {
190    let fn_name = &func.name(ctx.db);
191    let sugar: &[_] = if func.is_async(ctx.db) {
192        &[AsyncSugaring::Async, AsyncSugaring::Desugar]
193    } else if func.returns_impl_future(ctx.db) {
194        &[AsyncSugaring::Plain, AsyncSugaring::Resugar]
195    } else {
196        &[AsyncSugaring::Plain]
197    };
198    for &sugaring in sugar {
199        add_function_impl_(acc, ctx, replacement_range, func, impl_def, fn_name, sugaring);
200    }
201}
202
203fn add_function_impl_(
204    acc: &mut Completions,
205    ctx: &CompletionContext<'_, '_>,
206    replacement_range: TextRange,
207    func: hir::Function,
208    impl_def: hir::Impl,
209    fn_name: &Name,
210    async_sugaring: AsyncSugaring,
211) {
212    let async_ = if let AsyncSugaring::Async | AsyncSugaring::Resugar = async_sugaring {
213        "async "
214    } else {
215        ""
216    };
217    let label = format_smolstr!(
218        "{}fn {}({})",
219        async_,
220        fn_name.display(ctx.db, ctx.edition),
221        if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." }
222    );
223
224    let completion_kind = CompletionItemKind::SymbolKind(if func.has_self_param(ctx.db) {
225        SymbolKind::Method
226    } else {
227        SymbolKind::Function
228    });
229
230    let mut item = CompletionItem::new(completion_kind, replacement_range, label, ctx.edition);
231    item.lookup_by(format!("{}fn {}", async_, fn_name.display(ctx.db, ctx.edition)))
232        .set_documentation(func.docs(ctx.db))
233        .set_relevance(CompletionRelevance { exact_name_match: true, ..Default::default() });
234
235    if let Some(source) = ctx.sema.source(func)
236        && let Some(transformed_fn) =
237            get_transformed_fn(ctx, source.value, impl_def, async_sugaring)
238    {
239        let function_decl = function_declaration(ctx, &transformed_fn, source.file_id.macro_file());
240        let ws = if function_decl.contains('\n') { "\n" } else { " " };
241        match ctx.config.snippet_cap {
242            Some(cap) => {
243                let snippet = format!("{function_decl}{ws}{{\n    $0\n}}");
244                item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet));
245            }
246            None => {
247                let header = format!("{function_decl}{ws}{{");
248                item.text_edit(TextEdit::replace(replacement_range, header));
249            }
250        };
251        item.add_to(acc, ctx.db);
252    }
253}
254
255#[derive(Copy, Clone)]
256enum AsyncSugaring {
257    Desugar,
258    Resugar,
259    Async,
260    Plain,
261}
262
263/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
264fn get_transformed_assoc_item(
265    ctx: &CompletionContext<'_, '_>,
266    assoc_item: ast::AssocItem,
267    impl_def: hir::Impl,
268) -> Option<ast::AssocItem> {
269    let trait_ = impl_def.trait_(ctx.db)?;
270    let source_scope = &ctx.sema.scope(assoc_item.syntax())?;
271    let impl_source = ctx.sema.source(impl_def)?;
272    let target_scope = &ctx.sema.scope(impl_source.syntax().value)?;
273    let transform =
274        PathTransform::trait_impl(target_scope, source_scope, trait_, impl_source.value);
275
276    // FIXME: Paths in nested macros are not handled well. See
277    // `macro_generated_assoc_item2` test.
278    let assoc_item = ast::AssocItem::cast(transform.apply(assoc_item.syntax()))?;
279    let (editor, assoc_item) = SyntaxEditor::with_ast_node(&assoc_item);
280    assoc_item.remove_attrs_and_docs(&editor);
281    ast::AssocItem::cast(editor.finish().new_root().clone())
282}
283
284/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
285fn get_transformed_fn(
286    ctx: &CompletionContext<'_, '_>,
287    fn_: ast::Fn,
288    impl_def: hir::Impl,
289    async_: AsyncSugaring,
290) -> Option<ast::Fn> {
291    let trait_ = impl_def.trait_(ctx.db)?;
292    let source_scope = &ctx.sema.scope(fn_.syntax())?;
293    let impl_source = ctx.sema.source(impl_def)?;
294    let target_scope = &ctx.sema.scope(impl_source.syntax().value)?;
295    let transform =
296        PathTransform::trait_impl(target_scope, source_scope, trait_, impl_source.value);
297
298    let fn_ = fn_.reset_indent();
299    // FIXME: Paths in nested macros are not handled well. See
300    // `macro_generated_assoc_item2` test.
301    let fn_ = ast::Fn::cast(transform.apply(fn_.syntax()))?;
302    let (editor, fn_) = SyntaxEditor::with_ast_node(&fn_);
303    let factory = editor.make();
304    fn_.remove_attrs_and_docs(&editor);
305    match async_ {
306        AsyncSugaring::Desugar => {
307            match fn_.ret_type() {
308                Some(ret_ty) => {
309                    let ty = ret_ty.ty()?;
310                    editor.replace(
311                        ty.syntax(),
312                        factory.ty(&format!("impl Future<Output = {ty}>")).syntax(),
313                    );
314                }
315                None => {
316                    let ret_type = factory.ret_type(factory.ty("impl Future<Output = ()>"));
317                    editor.insert_with_whitespace(
318                        Position::after(fn_.param_list()?.syntax()),
319                        ret_type.syntax(),
320                    );
321                }
322            }
323            editor.delete(fn_.async_token()?);
324        }
325        AsyncSugaring::Resugar => {
326            let ty = fn_.ret_type()?.ty()?;
327            match &ty {
328                // best effort guessing here
329                ast::Type::ImplTraitType(t) => {
330                    let output = t.type_bound_list()?.bounds().find_map(|b| match b.ty()? {
331                        ast::Type::PathType(p) => {
332                            let p = p.path()?.segment()?;
333                            if p.name_ref()?.text() != "Future" {
334                                return None;
335                            }
336                            match p.generic_arg_list()?.generic_args().next()? {
337                                ast::GenericArg::AssocTypeArg(a)
338                                    if a.name_ref()?.text() == "Output" =>
339                                {
340                                    a.ty()
341                                }
342                                _ => None,
343                            }
344                        }
345                        _ => None,
346                    })?;
347                    if let ast::Type::TupleType(ty) = &output
348                        && ty.fields().next().is_none()
349                    {
350                        editor.delete(fn_.ret_type()?.syntax());
351                    } else {
352                        editor.replace(ty.syntax(), output.syntax());
353                    }
354                }
355                _ => (),
356            }
357            editor.insert_with_whitespace(
358                Position::first_child_of(fn_.syntax()),
359                factory.token(T![async]),
360            );
361        }
362        AsyncSugaring::Async | AsyncSugaring::Plain => (),
363    }
364    ast::Fn::cast(editor.finish().new_root().clone())
365}
366
367fn add_type_alias_impl(
368    acc: &mut Completions,
369    ctx: &CompletionContext<'_, '_>,
370    replacement_range: TextRange,
371    type_alias: hir::TypeAlias,
372    impl_def: hir::Impl,
373) {
374    let alias_name = type_alias.name(ctx.db).as_str().to_smolstr();
375
376    let label = format_smolstr!("type {alias_name} =");
377
378    let mut item =
379        CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label, ctx.edition);
380    item.lookup_by(format!("type {alias_name}"))
381        .set_documentation(type_alias.docs(ctx.db))
382        .set_relevance(CompletionRelevance { exact_name_match: true, ..Default::default() });
383
384    if let Some(source) = ctx.sema.source(type_alias) {
385        let assoc_item = ast::AssocItem::TypeAlias(source.value);
386        if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
387            let transformed_ty = match transformed_item {
388                ast::AssocItem::TypeAlias(ty) => ty,
389                _ => unreachable!(),
390            };
391
392            let start = transformed_ty.syntax().text_range().start();
393
394            let end = if let Some(end) =
395                transformed_ty.colon_token().map(|tok| tok.text_range().start())
396            {
397                end
398            } else if let Some(end) = transformed_ty.eq_token().map(|tok| tok.text_range().start())
399            {
400                end
401            } else if let Some(end) = transformed_ty
402                .where_clause()
403                .and_then(|wc| wc.where_token())
404                .map(|tok| tok.text_range().start())
405            {
406                end
407            } else if let Some(end) =
408                transformed_ty.semicolon_token().map(|tok| tok.text_range().start())
409            {
410                end
411            } else {
412                return;
413            };
414
415            let len = end - start;
416            let mut decl = transformed_ty.syntax().text().slice(..len).to_string();
417            decl.truncate(decl.trim_end().len());
418            decl.push_str(" = ");
419
420            let wc = transformed_ty
421                .where_clause()
422                .map(|wc| {
423                    let ws = wc
424                        .where_token()
425                        .and_then(|it| it.prev_token())
426                        .filter(|token| token.kind() == SyntaxKind::WHITESPACE)
427                        .map(|token| token.to_string())
428                        .unwrap_or_else(|| " ".into());
429                    format!("{ws}{wc}")
430                })
431                .unwrap_or_default();
432
433            match ctx.config.snippet_cap {
434                Some(cap) => {
435                    let snippet = format!("{decl}$0{wc};");
436                    item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet));
437                }
438                None => {
439                    decl.push_str(&wc);
440                    item.text_edit(TextEdit::replace(replacement_range, decl));
441                }
442            };
443            item.add_to(acc, ctx.db);
444        }
445    }
446}
447
448fn add_const_impl(
449    acc: &mut Completions,
450    ctx: &CompletionContext<'_, '_>,
451    replacement_range: TextRange,
452    const_: hir::Const,
453    impl_def: hir::Impl,
454) {
455    let const_name = const_.name(ctx.db).map(|n| n.display_no_db(ctx.edition).to_smolstr());
456
457    if let Some(const_name) = const_name
458        && let Some(source) = ctx.sema.source(const_)
459    {
460        let assoc_item = ast::AssocItem::Const(source.value);
461        if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
462            let transformed_const = match transformed_item {
463                ast::AssocItem::Const(const_) => const_,
464                _ => unreachable!(),
465            };
466
467            let label =
468                make_const_compl_syntax(ctx, &transformed_const, source.file_id.macro_file());
469            let replacement = format!("{label} ");
470
471            let mut item =
472                CompletionItem::new(SymbolKind::Const, replacement_range, label, ctx.edition);
473            item.lookup_by(format_smolstr!("const {const_name}"))
474                .set_documentation(const_.docs(ctx.db))
475                .set_relevance(CompletionRelevance {
476                    exact_name_match: true,
477                    ..Default::default()
478                });
479            match ctx.config.snippet_cap {
480                Some(cap) => item.snippet_edit(
481                    cap,
482                    TextEdit::replace(replacement_range, format!("{replacement}$0;")),
483                ),
484                None => item.text_edit(TextEdit::replace(replacement_range, replacement)),
485            };
486            item.add_to(acc, ctx.db);
487        }
488    }
489}
490
491fn make_const_compl_syntax(
492    ctx: &CompletionContext<'_, '_>,
493    const_: &ast::Const,
494    macro_file: Option<MacroCallId>,
495) -> SmolStr {
496    let const_ = if let Some(macro_file) = macro_file {
497        let span_map = ctx.db.expansion_span_map(macro_file);
498        prettify_macro_expansion(ctx.db, const_.syntax().clone(), span_map, ctx.krate.into())
499    } else {
500        const_.syntax().clone()
501    };
502
503    let start = const_.text_range().start();
504    let const_end = const_.text_range().end();
505
506    let end = const_
507        .children_with_tokens()
508        .find(|s| s.kind() == T![;] || s.kind() == T![=])
509        .map_or(const_end, |f| f.text_range().start());
510
511    let len = end - start;
512    let range = TextRange::new(0.into(), len);
513
514    let syntax = const_.text().slice(range).to_string();
515
516    format_smolstr!("{} =", syntax.trim_end())
517}
518
519fn function_declaration(
520    ctx: &CompletionContext<'_, '_>,
521    node: &ast::Fn,
522    macro_file: Option<MacroCallId>,
523) -> String {
524    let node = if let Some(macro_file) = macro_file {
525        let span_map = ctx.db.expansion_span_map(macro_file);
526        prettify_macro_expansion(ctx.db, node.syntax().clone(), span_map, ctx.krate.into())
527    } else {
528        node.syntax().clone()
529    };
530
531    let start = node.text_range().start();
532    let end = node.text_range().end();
533
534    let end = node
535        .last_child_or_token()
536        .filter(|s| s.kind() == T![;] || s.kind() == SyntaxKind::BLOCK_EXPR)
537        .map_or(end, |f| f.text_range().start());
538
539    let len = end - start;
540    let syntax = node.text().slice(..len).to_string();
541
542    syntax.trim_end().to_owned()
543}
544
545#[cfg(test)]
546mod tests {
547    use expect_test::expect;
548
549    use crate::tests::{check, check_edit, check_no_kw};
550
551    #[test]
552    fn no_completion_inside_fn() {
553        check_no_kw(
554            r"
555trait Test { fn test(); fn test2(); }
556struct T;
557
558impl Test for T {
559    fn test() {
560        t$0
561    }
562}
563",
564            expect![[r#"
565                sp Self  T
566                st T     T
567                tt Test
568                bt u32 u32
569            "#]],
570        );
571
572        check_no_kw(
573            r"
574trait Test { fn test(); fn test2(); }
575struct T;
576
577impl Test for T {
578    fn test() {
579        fn t$0
580    }
581}
582",
583            expect![[""]],
584        );
585
586        check_no_kw(
587            r"
588trait Test { fn test(); fn test2(); }
589struct T;
590
591impl Test for T {
592    fn test() {
593        fn $0
594    }
595}
596",
597            expect![[""]],
598        );
599
600        // https://github.com/rust-lang/rust-analyzer/pull/5976#issuecomment-692332191
601        check_no_kw(
602            r"
603trait Test { fn test(); fn test2(); }
604struct T;
605
606impl Test for T {
607    fn test() {
608        foo.$0
609    }
610}
611",
612            expect![[r#""#]],
613        );
614
615        check_no_kw(
616            r"
617trait Test { fn test(_: i32); fn test2(); }
618struct T;
619
620impl Test for T {
621    fn test(t$0)
622}
623",
624            expect![[r#"
625                sp Self
626                st T
627                bn &mut self
628                bn &self
629                bn mut self
630                bn self
631            "#]],
632        );
633
634        check_no_kw(
635            r"
636trait Test { fn test(_: fn()); fn test2(); }
637struct T;
638
639impl Test for T {
640    fn test(f: fn $0)
641}
642",
643            expect![[r#"
644                sp Self
645                st T
646            "#]],
647        );
648    }
649
650    #[test]
651    fn no_completion_inside_const() {
652        check_no_kw(
653            r"
654trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); }
655struct T;
656
657impl Test for T {
658    const TEST: fn $0
659}
660",
661            expect![[r#""#]],
662        );
663
664        check_no_kw(
665            r"
666trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
667struct T;
668
669impl Test for T {
670    const TEST: T$0
671}
672",
673            expect![[r#"
674                sp Self  T
675                st T     T
676                tt Test
677                bt u32 u32
678            "#]],
679        );
680
681        check_no_kw(
682            r"
683trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
684struct T;
685
686impl Test for T {
687    const TEST: u32 = f$0
688}
689",
690            expect![[r#"
691                sp Self  T
692                st T     T
693                tt Test
694                bt u32 u32
695            "#]],
696        );
697
698        check_no_kw(
699            r"
700trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
701struct T;
702
703impl Test for T {
704    const TEST: u32 = {
705        t$0
706    };
707}
708",
709            expect![[r#"
710                sp Self  T
711                st T     T
712                tt Test
713                bt u32 u32
714            "#]],
715        );
716
717        check_no_kw(
718            r"
719trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
720struct T;
721
722impl Test for T {
723    const TEST: u32 = {
724        fn $0
725    };
726}
727",
728            expect![[""]],
729        );
730
731        check_no_kw(
732            r"
733trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
734struct T;
735
736impl Test for T {
737    const TEST: u32 = {
738        fn t$0
739    };
740}
741",
742            expect![[""]],
743        );
744    }
745
746    #[test]
747    fn no_completion_inside_type() {
748        check_no_kw(
749            r"
750trait Test { type Test; type Test2; fn test(); }
751struct T;
752
753impl Test for T {
754    type Test = T$0;
755}
756",
757            expect![[r#"
758                sp Self  T
759                st T     T
760                tt Test
761                bt u32 u32
762            "#]],
763        );
764
765        check_no_kw(
766            r"
767trait Test { type Test; type Test2; fn test(); }
768struct T;
769
770impl Test for T {
771    type Test = fn $0;
772}
773",
774            expect![[r#""#]],
775        );
776    }
777
778    #[test]
779    fn name_ref_single_function() {
780        check_edit(
781            "fn test",
782            r#"
783trait Test {
784    fn test();
785}
786struct T;
787
788impl Test for T {
789    t$0
790}
791"#,
792            r#"
793trait Test {
794    fn test();
795}
796struct T;
797
798impl Test for T {
799    fn test() {
800    $0
801}
802}
803"#,
804        );
805    }
806
807    #[test]
808    fn single_function() {
809        check_edit(
810            "fn test",
811            r#"
812trait Test {
813    fn test();
814}
815struct T;
816
817impl Test for T {
818    fn t$0
819}
820"#,
821            r#"
822trait Test {
823    fn test();
824}
825struct T;
826
827impl Test for T {
828    fn test() {
829    $0
830}
831}
832"#,
833        );
834    }
835
836    #[test]
837    fn generic_fn() {
838        check_edit(
839            "fn foo",
840            r#"
841trait Test {
842    fn foo<T>();
843}
844struct T;
845
846impl Test for T {
847    fn f$0
848}
849"#,
850            r#"
851trait Test {
852    fn foo<T>();
853}
854struct T;
855
856impl Test for T {
857    fn foo<T>() {
858    $0
859}
860}
861"#,
862        );
863        check_edit(
864            "fn foo",
865            r#"
866trait Test {
867    fn foo<T>() where T: Into<String>;
868}
869struct T;
870
871impl Test for T {
872    fn f$0
873}
874"#,
875            r#"
876trait Test {
877    fn foo<T>() where T: Into<String>;
878}
879struct T;
880
881impl Test for T {
882    fn foo<T>() where T: Into<String> {
883    $0
884}
885}
886"#,
887        );
888    }
889
890    #[test]
891    fn associated_type() {
892        check_edit(
893            "type SomeType",
894            r#"
895trait Test {
896    type SomeType;
897}
898
899impl Test for () {
900    type S$0
901}
902"#,
903            "
904trait Test {
905    type SomeType;
906}
907
908impl Test for () {
909    type SomeType = $0;\n\
910}
911",
912        );
913        check_edit(
914            "type SomeType",
915            r#"
916trait Test {
917    type SomeType;
918}
919
920impl Test for () {
921    type$0
922}
923"#,
924            "
925trait Test {
926    type SomeType;
927}
928
929impl Test for () {
930    type SomeType = $0;\n\
931}
932",
933        );
934    }
935
936    #[test]
937    fn associated_const() {
938        check_edit(
939            "const SOME_CONST",
940            r#"
941trait Test {
942    const SOME_CONST: u16;
943}
944
945impl Test for () {
946    const S$0
947}
948"#,
949            "
950trait Test {
951    const SOME_CONST: u16;
952}
953
954impl Test for () {
955    const SOME_CONST: u16 = $0;\n\
956}
957",
958        );
959
960        check_edit(
961            "const SOME_CONST",
962            r#"
963trait Test {
964    const SOME_CONST: u16 = 92;
965}
966
967impl Test for () {
968    const S$0
969}
970"#,
971            "
972trait Test {
973    const SOME_CONST: u16 = 92;
974}
975
976impl Test for () {
977    const SOME_CONST: u16 = $0;\n\
978}
979",
980        );
981    }
982
983    #[test]
984    fn fn_with_lifetimes() {
985        check_edit(
986            "fn foo",
987            r#"
988trait Test<'a, 'b, T> {
989    fn foo(&self, a: &'a T, b: &'b T) -> &'a T;
990}
991
992impl<'x, 'y, A> Test<'x, 'y, A> for () {
993    t$0
994}
995"#,
996            r#"
997trait Test<'a, 'b, T> {
998    fn foo(&self, a: &'a T, b: &'b T) -> &'a T;
999}
1000
1001impl<'x, 'y, A> Test<'x, 'y, A> for () {
1002    fn foo(&self, a: &'x A, b: &'y A) -> &'x A {
1003    $0
1004}
1005}
1006"#,
1007        );
1008    }
1009
1010    #[test]
1011    fn complete_without_name() {
1012        let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| {
1013            check_edit(
1014                completion,
1015                &format!(
1016                    r#"
1017trait Test {{
1018    type Foo;
1019    const CONST: u16;
1020    fn bar();
1021}}
1022struct T;
1023
1024impl Test for T {{
1025    {hint}
1026    {next_sibling}
1027}}
1028"#
1029                ),
1030                &format!(
1031                    r#"
1032trait Test {{
1033    type Foo;
1034    const CONST: u16;
1035    fn bar();
1036}}
1037struct T;
1038
1039impl Test for T {{
1040    {completed}
1041    {next_sibling}
1042}}
1043"#
1044                ),
1045            )
1046        };
1047
1048        // Enumerate some possible next siblings.
1049        for next_sibling in [
1050            "",
1051            "fn other_fn() {}", // `const $0 fn` -> `const fn`
1052            "type OtherType = i32;",
1053            "const OTHER_CONST: i32 = 0;",
1054            "async fn other_fn() {}",
1055            "unsafe fn other_fn() {}",
1056            "default fn other_fn() {}",
1057            "default type OtherType = i32;",
1058            "default const OTHER_CONST: i32 = 0;",
1059        ] {
1060            test("fn bar", "fn $0", "fn bar() {\n    $0\n}", next_sibling);
1061            test("type Foo", "type $0", "type Foo = $0;", next_sibling);
1062            test("const CONST", "const $0", "const CONST: u16 = $0;", next_sibling);
1063        }
1064    }
1065
1066    #[test]
1067    fn snippet_does_not_overwrite_comment_or_attr() {
1068        let test = |completion: &str, hint: &str, completed: &str| {
1069            check_edit(
1070                completion,
1071                &format!(
1072                    r#"
1073trait Foo {{
1074    type Type;
1075    fn function();
1076    const CONST: i32 = 0;
1077}}
1078struct T;
1079
1080impl Foo for T {{
1081    // Comment
1082    #[bar]
1083    {hint}
1084}}
1085"#
1086                ),
1087                &format!(
1088                    r#"
1089trait Foo {{
1090    type Type;
1091    fn function();
1092    const CONST: i32 = 0;
1093}}
1094struct T;
1095
1096impl Foo for T {{
1097    // Comment
1098    #[bar]
1099    {completed}
1100}}
1101"#
1102                ),
1103            )
1104        };
1105        test("fn function", "fn f$0", "fn function() {\n    $0\n}");
1106        test("type Type", "type T$0", "type Type = $0;");
1107        test("const CONST", "const C$0", "const CONST: i32 = $0;");
1108    }
1109
1110    #[test]
1111    fn generics_are_inlined_in_return_type() {
1112        check_edit(
1113            "fn function",
1114            r#"
1115trait Foo<T> {
1116    fn function() -> T;
1117}
1118struct Bar;
1119
1120impl Foo<u32> for Bar {
1121    fn f$0
1122}
1123"#,
1124            r#"
1125trait Foo<T> {
1126    fn function() -> T;
1127}
1128struct Bar;
1129
1130impl Foo<u32> for Bar {
1131    fn function() -> u32 {
1132    $0
1133}
1134}
1135"#,
1136        )
1137    }
1138
1139    #[test]
1140    fn generics_are_inlined_in_parameter() {
1141        check_edit(
1142            "fn function",
1143            r#"
1144trait Foo<T> {
1145    fn function(bar: T);
1146}
1147struct Bar;
1148
1149impl Foo<u32> for Bar {
1150    fn f$0
1151}
1152"#,
1153            r#"
1154trait Foo<T> {
1155    fn function(bar: T);
1156}
1157struct Bar;
1158
1159impl Foo<u32> for Bar {
1160    fn function(bar: u32) {
1161    $0
1162}
1163}
1164"#,
1165        )
1166    }
1167
1168    #[test]
1169    fn generics_are_inlined_when_part_of_other_types() {
1170        check_edit(
1171            "fn function",
1172            r#"
1173trait Foo<T> {
1174    fn function(bar: Vec<T>);
1175}
1176struct Bar;
1177
1178impl Foo<u32> for Bar {
1179    fn f$0
1180}
1181"#,
1182            r#"
1183trait Foo<T> {
1184    fn function(bar: Vec<T>);
1185}
1186struct Bar;
1187
1188impl Foo<u32> for Bar {
1189    fn function(bar: Vec<u32>) {
1190    $0
1191}
1192}
1193"#,
1194        )
1195    }
1196
1197    #[test]
1198    fn generics_are_inlined_complex() {
1199        check_edit(
1200            "fn function",
1201            r#"
1202trait Foo<T, U, V> {
1203    fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
1204}
1205struct Bar;
1206
1207impl Foo<u32, Vec<usize>, u8> for Bar {
1208    fn f$0
1209}
1210"#,
1211            r#"
1212trait Foo<T, U, V> {
1213    fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
1214}
1215struct Bar;
1216
1217impl Foo<u32, Vec<usize>, u8> for Bar {
1218    fn function(bar: Vec<u32>, baz: Vec<usize>) -> Arc<Vec<u8>> {
1219    $0
1220}
1221}
1222"#,
1223        )
1224    }
1225
1226    #[test]
1227    fn generics_are_inlined_in_associated_const() {
1228        check_edit(
1229            "const BAR",
1230            r#"
1231trait Foo<T> {
1232    const BAR: T;
1233}
1234struct Bar;
1235
1236impl Foo<u32> for Bar {
1237    const B$0
1238}
1239"#,
1240            r#"
1241trait Foo<T> {
1242    const BAR: T;
1243}
1244struct Bar;
1245
1246impl Foo<u32> for Bar {
1247    const BAR: u32 = $0;
1248}
1249"#,
1250        )
1251    }
1252
1253    #[test]
1254    fn generics_are_inlined_in_where_clause() {
1255        check_edit(
1256            "fn function",
1257            r#"
1258trait SomeTrait<T> {}
1259
1260trait Foo<T> {
1261    fn function()
1262    where Self: SomeTrait<T>;
1263}
1264struct Bar;
1265
1266impl Foo<u32> for Bar {
1267    fn f$0
1268}
1269"#,
1270            r#"
1271trait SomeTrait<T> {}
1272
1273trait Foo<T> {
1274    fn function()
1275    where Self: SomeTrait<T>;
1276}
1277struct Bar;
1278
1279impl Foo<u32> for Bar {
1280    fn function()
1281where Self: SomeTrait<u32>
1282{
1283    $0
1284}
1285}
1286"#,
1287        )
1288    }
1289
1290    #[test]
1291    fn works_directly_in_impl() {
1292        check_no_kw(
1293            r#"
1294trait Tr {
1295    fn required();
1296}
1297
1298impl Tr for () {
1299    $0
1300}
1301"#,
1302            expect![[r#"
1303            fn fn required()
1304        "#]],
1305        );
1306        check_no_kw(
1307            r#"
1308trait Tr {
1309    fn provided() {}
1310    fn required();
1311}
1312
1313impl Tr for () {
1314    fn provided() {}
1315    $0
1316}
1317"#,
1318            expect![[r#"
1319            fn fn required()
1320        "#]],
1321        );
1322    }
1323
1324    #[test]
1325    fn fixes_up_macro_generated() {
1326        check_edit(
1327            "fn foo",
1328            r#"
1329macro_rules! noop {
1330    ($($item: item)*) => {
1331        $($item)*
1332    }
1333}
1334
1335noop! {
1336    trait Foo {
1337        fn foo(&mut self, bar: i64, baz: &mut u32) -> Result<(), u32>;
1338    }
1339}
1340
1341struct Test;
1342
1343impl Foo for Test {
1344    $0
1345}
1346"#,
1347            r#"
1348macro_rules! noop {
1349    ($($item: item)*) => {
1350        $($item)*
1351    }
1352}
1353
1354noop! {
1355    trait Foo {
1356        fn foo(&mut self, bar: i64, baz: &mut u32) -> Result<(), u32>;
1357    }
1358}
1359
1360struct Test;
1361
1362impl Foo for Test {
1363    fn foo(&mut self,bar: i64,baz: &mut u32) -> Result<(),u32> {
1364    $0
1365}
1366}
1367"#,
1368        );
1369    }
1370
1371    #[test]
1372    fn macro_generated_assoc_item() {
1373        check_edit(
1374            "fn method",
1375            r#"
1376macro_rules! ty { () => { i32 } }
1377trait SomeTrait { type Output; }
1378impl SomeTrait for i32 { type Output = i64; }
1379macro_rules! define_method {
1380    () => {
1381        fn method(&mut self, params: <ty!() as SomeTrait>::Output);
1382    };
1383}
1384trait AnotherTrait { define_method!(); }
1385impl AnotherTrait for () {
1386    $0
1387}
1388"#,
1389            r#"
1390macro_rules! ty { () => { i32 } }
1391trait SomeTrait { type Output; }
1392impl SomeTrait for i32 { type Output = i64; }
1393macro_rules! define_method {
1394    () => {
1395        fn method(&mut self, params: <ty!() as SomeTrait>::Output);
1396    };
1397}
1398trait AnotherTrait { define_method!(); }
1399impl AnotherTrait for () {
1400    fn method(&mut self,params: <ty!()as SomeTrait>::Output) {
1401    $0
1402}
1403}
1404"#,
1405        );
1406    }
1407
1408    // FIXME: `T` in `ty!(T)` should be replaced by `PathTransform`.
1409    #[test]
1410    fn macro_generated_assoc_item2() {
1411        check_edit(
1412            "fn method",
1413            r#"
1414macro_rules! ty { ($me:ty) => { $me } }
1415trait SomeTrait { type Output; }
1416impl SomeTrait for i32 { type Output = i64; }
1417macro_rules! define_method {
1418    ($t:ty) => {
1419        fn method(&mut self, params: <ty!($t) as SomeTrait>::Output);
1420    };
1421}
1422trait AnotherTrait<T: SomeTrait> { define_method!(T); }
1423impl AnotherTrait<i32> for () {
1424    $0
1425}
1426"#,
1427            r#"
1428macro_rules! ty { ($me:ty) => { $me } }
1429trait SomeTrait { type Output; }
1430impl SomeTrait for i32 { type Output = i64; }
1431macro_rules! define_method {
1432    ($t:ty) => {
1433        fn method(&mut self, params: <ty!($t) as SomeTrait>::Output);
1434    };
1435}
1436trait AnotherTrait<T: SomeTrait> { define_method!(T); }
1437impl AnotherTrait<i32> for () {
1438    fn method(&mut self,params: <ty!(T)as SomeTrait>::Output) {
1439    $0
1440}
1441}
1442"#,
1443        );
1444    }
1445
1446    #[test]
1447    fn includes_gat_generics() {
1448        check_edit(
1449            "type Ty",
1450            r#"
1451trait Tr<'b> {
1452    type Ty<'a: 'b, T: Copy, const C: usize>;
1453}
1454
1455impl<'b> Tr<'b> for () {
1456    $0
1457}
1458"#,
1459            r#"
1460trait Tr<'b> {
1461    type Ty<'a: 'b, T: Copy, const C: usize>;
1462}
1463
1464impl<'b> Tr<'b> for () {
1465    type Ty<'a: 'b, T: Copy, const C: usize> = $0;
1466}
1467"#,
1468        );
1469    }
1470    #[test]
1471    fn includes_where_clause() {
1472        check_edit(
1473            "type Ty",
1474            r#"
1475trait Tr {
1476    type Ty where Self: Copy;
1477}
1478
1479impl Tr for () {
1480    $0
1481}
1482"#,
1483            r#"
1484trait Tr {
1485    type Ty where Self: Copy;
1486}
1487
1488impl Tr for () {
1489    type Ty = $0 where Self: Copy;
1490}
1491"#,
1492        );
1493    }
1494
1495    #[test]
1496    fn strips_comments() {
1497        check_edit(
1498            "fn func",
1499            r#"
1500trait Tr {
1501    /// docs
1502    #[attr]
1503    fn func();
1504}
1505impl Tr for () {
1506    $0
1507}
1508"#,
1509            r#"
1510trait Tr {
1511    /// docs
1512    #[attr]
1513    fn func();
1514}
1515impl Tr for () {
1516    fn func() {
1517    $0
1518}
1519}
1520"#,
1521        );
1522        check_edit(
1523            "const C",
1524            r#"
1525trait Tr {
1526    /// docs
1527    #[attr]
1528    const C: usize;
1529}
1530impl Tr for () {
1531    $0
1532}
1533"#,
1534            r#"
1535trait Tr {
1536    /// docs
1537    #[attr]
1538    const C: usize;
1539}
1540impl Tr for () {
1541    const C: usize = $0;
1542}
1543"#,
1544        );
1545        check_edit(
1546            "type Item",
1547            r#"
1548trait Tr {
1549    /// docs
1550    #[attr]
1551    type Item;
1552}
1553impl Tr for () {
1554    $0
1555}
1556"#,
1557            r#"
1558trait Tr {
1559    /// docs
1560    #[attr]
1561    type Item;
1562}
1563impl Tr for () {
1564    type Item = $0;
1565}
1566"#,
1567        );
1568    }
1569
1570    #[test]
1571    fn impl_fut() {
1572        check_edit(
1573            "fn foo",
1574            r#"
1575//- minicore: future, send, sized
1576use core::future::Future;
1577
1578trait DesugaredAsyncTrait {
1579    fn foo(&self) -> impl Future<Output = usize> + Send;
1580}
1581
1582impl DesugaredAsyncTrait for () {
1583    $0
1584}
1585"#,
1586            r#"
1587use core::future::Future;
1588
1589trait DesugaredAsyncTrait {
1590    fn foo(&self) -> impl Future<Output = usize> + Send;
1591}
1592
1593impl DesugaredAsyncTrait for () {
1594    fn foo(&self) -> impl Future<Output = usize> + Send {
1595    $0
1596}
1597}
1598"#,
1599        );
1600    }
1601
1602    #[test]
1603    fn impl_fut_resugared() {
1604        check_edit(
1605            "async fn foo",
1606            r#"
1607//- minicore: future, send, sized
1608use core::future::Future;
1609
1610trait DesugaredAsyncTrait {
1611    fn foo(&self) -> impl Future<Output = usize> + Send;
1612}
1613
1614impl DesugaredAsyncTrait for () {
1615    $0
1616}
1617"#,
1618            r#"
1619use core::future::Future;
1620
1621trait DesugaredAsyncTrait {
1622    fn foo(&self) -> impl Future<Output = usize> + Send;
1623}
1624
1625impl DesugaredAsyncTrait for () {
1626    async fn foo(&self) -> usize {
1627    $0
1628}
1629}
1630"#,
1631        );
1632
1633        check_edit(
1634            "async fn foo",
1635            r#"
1636//- minicore: future, send, sized
1637use core::future::Future;
1638
1639trait DesugaredAsyncTrait {
1640    fn foo(&self) -> impl Future<Output = ()> + Send;
1641}
1642
1643impl DesugaredAsyncTrait for () {
1644    $0
1645}
1646"#,
1647            r#"
1648use core::future::Future;
1649
1650trait DesugaredAsyncTrait {
1651    fn foo(&self) -> impl Future<Output = ()> + Send;
1652}
1653
1654impl DesugaredAsyncTrait for () {
1655    async fn foo(&self) {
1656    $0
1657}
1658}
1659"#,
1660        );
1661    }
1662
1663    #[test]
1664    fn async_desugared() {
1665        check_edit(
1666            "fn foo",
1667            r#"
1668//- minicore: future, send, sized
1669use core::future::Future;
1670
1671trait DesugaredAsyncTrait {
1672    async fn foo(&self) -> usize;
1673}
1674
1675impl DesugaredAsyncTrait for () {
1676    $0
1677}
1678"#,
1679            r#"
1680use core::future::Future;
1681
1682trait DesugaredAsyncTrait {
1683    async fn foo(&self) -> usize;
1684}
1685
1686impl DesugaredAsyncTrait for () {
1687     fn foo(&self) -> impl Future<Output = usize> {
1688    $0
1689}
1690}
1691"#,
1692        );
1693    }
1694
1695    #[test]
1696    fn async_() {
1697        check_edit(
1698            "async fn foo",
1699            r#"
1700//- minicore: future, send, sized
1701use core::future::Future;
1702
1703trait DesugaredAsyncTrait {
1704    async fn foo(&self) -> usize;
1705}
1706
1707impl DesugaredAsyncTrait for () {
1708    $0
1709}
1710"#,
1711            r#"
1712use core::future::Future;
1713
1714trait DesugaredAsyncTrait {
1715    async fn foo(&self) -> usize;
1716}
1717
1718impl DesugaredAsyncTrait for () {
1719    async fn foo(&self) -> usize {
1720    $0
1721}
1722}
1723"#,
1724        );
1725    }
1726
1727    #[test]
1728    fn within_attr_macro() {
1729        check(
1730            r#"
1731//- proc_macros: identity
1732trait Trait {
1733    fn foo(&self) {}
1734    fn bar(&self) {}
1735    fn baz(&self) {}
1736}
1737
1738#[proc_macros::identity]
1739impl Trait for () {
1740    f$0
1741}
1742                "#,
1743            expect![[r#"
1744                me fn bar(..)
1745                me fn baz(..)
1746                me fn foo(..)
1747                md proc_macros::
1748                kw crate::
1749                kw self::
1750            "#]],
1751        );
1752        check(
1753            r#"
1754//- proc_macros: identity
1755trait Trait {
1756    fn foo(&self) {}
1757    fn bar(&self) {}
1758    fn baz(&self) {}
1759}
1760
1761#[proc_macros::identity]
1762impl Trait for () {
1763    fn $0
1764}
1765        "#,
1766            expect![[r#"
1767                me fn bar(..)
1768                me fn baz(..)
1769                me fn foo(..)
1770            "#]],
1771        );
1772    }
1773}