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