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