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