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