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