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