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