1use std::ops::Not;
2
3use crate::{
4 assist_context::{AssistContext, Assists},
5 utils::convert_param_list_to_arg_list,
6};
7use either::Either;
8use hir::{HasVisibility, db::HirDatabase};
9use ide_db::{
10 FxHashMap, FxHashSet,
11 assists::{AssistId, GroupLabel},
12 path_transform::PathTransform,
13 syntax_helpers::suggest_name,
14};
15use itertools::Itertools;
16use syntax::{
17 AstNode, Edition, SmolStr, SyntaxElement, SyntaxKind, ToSmolStr,
18 ast::{
19 self, AssocItem, GenericArgList, GenericParamList, HasAttrs, HasGenericArgs,
20 HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path,
21 WherePred,
22 edit::{self, AstNodeEdit},
23 syntax_factory::SyntaxFactory,
24 },
25 syntax_editor::SyntaxEditor,
26};
27
28pub(crate) fn generate_delegate_trait(
90 acc: &mut Assists,
91 ctx: &AssistContext<'_, '_>,
92) -> Option<()> {
93 if !ctx.config.code_action_grouping {
94 return None;
95 }
96
97 let strukt = Struct::new(ctx.find_node_at_offset::<ast::Struct>()?)?;
98
99 let field: Field = match ctx.find_node_at_offset::<ast::RecordField>() {
100 Some(field) => Field::new(ctx, Either::Left(field))?,
101 None => {
102 let field = ctx.find_node_at_offset::<ast::TupleField>()?;
103 let field_list = ctx.find_node_at_offset::<ast::TupleFieldList>()?;
104 Field::new(ctx, either::Right((field, field_list)))?
105 }
106 };
107
108 strukt.delegate(field, acc, ctx);
109 Some(())
110}
111
112#[derive(Debug)]
114struct Field {
115 name: String,
116 ty: ast::Type,
117 range: syntax::TextRange,
118 impls: Vec<Delegee>,
119 edition: Edition,
120}
121
122impl Field {
123 pub(crate) fn new(
124 ctx: &AssistContext<'_, '_>,
125 f: Either<ast::RecordField, (ast::TupleField, ast::TupleFieldList)>,
126 ) -> Option<Field> {
127 let db = ctx.sema.db;
128
129 let module = ctx.sema.file_to_module_def(ctx.vfs_file_id())?;
130 let edition = module.krate(ctx.db()).edition(ctx.db());
131
132 let (name, range, ty) = match f {
133 Either::Left(f) => {
134 let name = f.name()?.to_string();
135 (name, f.syntax().text_range(), f.ty()?)
136 }
137 Either::Right((f, l)) => {
138 let name = l.fields().position(|it| it == f)?.to_string();
139 (name, f.syntax().text_range(), f.ty()?)
140 }
141 };
142
143 let hir_ty = ctx.sema.resolve_type(&ty)?;
144 let type_impls = hir::Impl::all_for_type(db, hir_ty.clone());
145 let mut impls = Vec::with_capacity(type_impls.len());
146
147 if let Some(tp) = hir_ty.as_type_param(db) {
148 for tb in tp.trait_bounds(db) {
149 impls.push(Delegee::Bound(tb));
150 }
151 };
152
153 for imp in type_impls {
154 if let Some(tr) = imp.trait_(db).filter(|tr| tr.is_visible_from(db, module)) {
155 impls.push(Delegee::Impls(tr, imp))
156 }
157 }
158
159 Some(Field { name, ty, range, impls, edition })
160 }
161}
162
163#[derive(Debug)]
169enum Delegee {
170 Bound(hir::Trait),
171 Impls(hir::Trait, hir::Impl),
172}
173
174impl Delegee {
175 fn trait_(&self) -> &hir::Trait {
176 match self {
177 Delegee::Bound(it) | Delegee::Impls(it, _) => it,
178 }
179 }
180
181 fn signature(&self, db: &dyn HirDatabase, edition: Edition) -> String {
182 let mut s = String::new();
183 let it = self.trait_();
184
185 for m in it.module(db).path_to_root(db).iter().rev() {
186 if let Some(name) = m.name(db) {
187 s.push_str(&format!("{}::", name.display_no_db(edition).to_smolstr()));
188 }
189 }
190
191 s.push_str(&it.name(db).display_no_db(edition).to_smolstr());
192 s
193 }
194}
195
196struct Struct {
198 strukt: ast::Struct,
199 name: ast::Name,
200}
201
202impl Struct {
203 pub(crate) fn new(s: ast::Struct) -> Option<Self> {
204 let name = s.name()?;
205 Some(Struct { name, strukt: s })
206 }
207
208 pub(crate) fn delegate(&self, field: Field, acc: &mut Assists, ctx: &AssistContext<'_, '_>) {
209 let db = ctx.db();
210
211 for (index, delegee) in field.impls.iter().enumerate() {
212 let trait_ = delegee.trait_();
213
214 if has_self_type(*trait_, ctx) {
218 continue;
219 }
220
221 let signature = delegee.signature(db, field.edition);
227
228 let Some(delegate) =
229 generate_impl(ctx, self, &field.ty, &field.name, delegee, field.edition)
230 else {
231 continue;
232 };
233
234 acc.add_group(
235 &GroupLabel(format!("Generate delegate trait impls for field `{}`", field.name)),
236 AssistId(
237 "generate_delegate_trait",
238 ide_db::assists::AssistKind::Generate,
239 Some(index),
240 ),
241 format!("Generate delegate trait impl `{}` for `{}`", signature, field.name),
242 field.range,
243 |builder| {
244 builder.insert(
245 self.strukt.syntax().text_range().end(),
246 format!("\n\n{}", delegate.syntax()),
247 );
248 },
249 );
250 }
251 }
252}
253
254fn generate_impl(
255 ctx: &AssistContext<'_, '_>,
256 strukt: &Struct,
257 field_ty: &ast::Type,
258 field_name: &str,
259 delegee: &Delegee,
260 edition: Edition,
261) -> Option<ast::Impl> {
262 let make = SyntaxFactory::without_mappings();
263 let db = ctx.db();
264 let ast_strukt = &strukt.strukt;
265 let strukt_ty = make.ty_path(make.ident_path(&strukt.name.to_string())).into();
266 let strukt_params = ast_strukt.generic_param_list();
267
268 match delegee {
269 Delegee::Bound(delegee) => {
270 let bound_def = ctx.sema.source(delegee.to_owned())?.value;
271 let bound_params = bound_def.generic_param_list();
272
273 let delegate = make.impl_trait(
274 None,
275 delegee.is_unsafe(db),
276 bound_params.clone(),
277 bound_params.map(|params| params.to_generic_args(&make)),
278 strukt_params.clone(),
279 strukt_params.map(|params| params.to_generic_args(&make)),
280 delegee.is_auto(db),
281 make.ty(&delegee.name(db).display_no_db(edition).to_smolstr()),
282 strukt_ty,
283 bound_def.where_clause(),
284 ast_strukt.where_clause(),
285 None,
286 );
287
288 let qualified_path_type =
290 make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
291
292 let assoc_items: Option<Vec<ast::AssocItem>> = bound_def.assoc_item_list().map(|ai| {
294 ai.assoc_items()
295 .filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
296 .filter_map(|item| {
297 process_assoc_item(item, qualified_path_type.clone(), field_name)
298 })
299 .collect()
300 });
301
302 let delegate = finalize_delegate(&make, &delegate, assoc_items, false)?;
303
304 let target_scope = ctx.sema.scope(strukt.strukt.syntax())?;
305 let source_scope = ctx.sema.scope(bound_def.syntax())?;
306 let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
307 ast::Impl::cast(transform.apply(delegate.syntax()))
308 }
309 Delegee::Impls(trait_, old_impl) => {
310 let old_impl = ctx.sema.source(old_impl.to_owned())?.value;
311 let old_impl_params = old_impl.generic_param_list();
312
313 let strukt_params = resolve_name_conflicts(strukt_params, &old_impl_params);
319 let (field_ty, ty_where_clause) = match &strukt_params {
320 Some(strukt_params) => {
321 let args = strukt_params.to_generic_args(&make);
322 let field_ty = rename_strukt_args(ctx, ast_strukt, field_ty, &args)?;
323 let where_clause = ast_strukt
324 .where_clause()
325 .and_then(|wc| rename_strukt_args(ctx, ast_strukt, &wc, &args));
326 (field_ty, where_clause)
327 }
328 None => (field_ty.clone(), None),
329 };
330
331 let old_impl_trait_args = old_impl
339 .trait_()?
340 .generic_arg_list()
341 .map(|l| l.generic_args().map(|arg| arg.to_string()))
342 .map_or_else(FxHashSet::default, |it| it.collect());
343
344 let trait_gen_params = remove_instantiated_params(
345 &old_impl.self_ty()?,
346 old_impl_params.clone(),
347 &old_impl_trait_args,
348 );
349
350 let (transform_args, trait_gen_params) = generate_args_for_impl(
352 &make,
353 old_impl_params,
354 &old_impl.self_ty()?,
355 &field_ty,
356 trait_gen_params,
357 &old_impl_trait_args,
358 );
359
360 let trait_gen_args =
363 old_impl.trait_()?.generic_arg_list().and_then(|mut trait_args| {
364 let trait_args = &mut trait_args;
365 if let Some(new_args) = transform_impl(
366 ctx,
367 ast_strukt,
368 &old_impl,
369 &transform_args,
370 trait_args.clone(),
371 ) {
372 *trait_args = new_args.clone();
373 Some(new_args)
374 } else {
375 None
376 }
377 });
378
379 let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args(&make));
380 let path_type = make.ty(&trait_.name(db).display_no_db(edition).to_smolstr());
381 let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?;
382 let delegate = make.impl_trait(
384 None,
385 trait_.is_unsafe(db),
386 trait_gen_params,
387 trait_gen_args,
388 strukt_params,
389 type_gen_args,
390 trait_.is_auto(db),
391 path_type,
392 strukt_ty,
393 old_impl.where_clause(),
394 ty_where_clause,
395 None,
396 );
397 let qualified_path_type =
399 make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
400
401 let assoc_items: Option<Vec<ast::AssocItem>> = old_impl.assoc_item_list().map(|ail| {
403 ail.assoc_items()
404 .filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
405 .filter_map(|item| {
406 let item =
407 transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?;
408 process_assoc_item(item, qualified_path_type.clone(), field_name)
409 })
410 .collect()
411 });
412
413 finalize_delegate(&make, &delegate, assoc_items, true)
414 }
415 }
416}
417
418fn transform_impl<N: ast::AstNode>(
419 ctx: &AssistContext<'_, '_>,
420 strukt: &ast::Struct,
421 old_impl: &ast::Impl,
422 args: &Option<GenericArgList>,
423 syntax: N,
424) -> Option<N> {
425 let source_scope = ctx.sema.scope(old_impl.self_ty()?.syntax())?;
426 let target_scope = ctx.sema.scope(strukt.syntax())?;
427 let hir_old_impl = ctx.sema.to_impl_def(old_impl)?;
428
429 let transform = args.as_ref().map_or_else(
430 || PathTransform::generic_transformation(&target_scope, &source_scope),
431 |args| {
432 PathTransform::impl_transformation(
433 &target_scope,
434 &source_scope,
435 hir_old_impl,
436 args.clone(),
437 )
438 },
439 );
440
441 N::cast(transform.apply(syntax.syntax()))
442}
443
444fn generic_param_name(param: &ast::GenericParam) -> Option<String> {
446 match param {
447 ast::GenericParam::TypeParam(t) => t.name().map(|n| n.to_string()),
448 ast::GenericParam::ConstParam(c) => c.name().map(|n| n.to_string()),
449 ast::GenericParam::LifetimeParam(l) => l.lifetime().map(|lt| lt.to_string()),
450 }
451}
452
453fn filter_generic_params(
455 gpl: ast::GenericParamList,
456 names_to_remove: &FxHashSet<String>,
457) -> Option<ast::GenericParamList> {
458 let remaining_params: Vec<_> = gpl
459 .generic_params()
460 .filter(|param| {
461 generic_param_name(param).is_none_or(|name| !names_to_remove.contains(&name))
462 })
463 .collect();
464
465 if remaining_params.is_empty() {
466 None
467 } else {
468 let make = SyntaxFactory::without_mappings();
469 Some(make.generic_param_list(remaining_params))
470 }
471}
472
473fn remove_instantiated_params(
474 self_ty: &ast::Type,
475 old_impl_params: Option<GenericParamList>,
476 old_trait_args: &FxHashSet<String>,
477) -> Option<GenericParamList> {
478 match self_ty {
479 ast::Type::PathType(path_type) => {
480 old_impl_params.and_then(|gpl| {
481 let args_to_remove: FxHashSet<String> = path_type
483 .path()?
484 .segments()
485 .filter_map(|seg| seg.generic_arg_list())
486 .flat_map(|it| it.generic_args())
487 .filter(|arg| !old_trait_args.contains(&arg.to_string()))
491 .map(|arg| arg.to_string())
492 .collect();
493
494 filter_generic_params(gpl, &args_to_remove)
495 })
496 }
497 _ => old_impl_params,
498 }
499}
500
501fn remove_useless_where_clauses(editor: &SyntaxEditor, delegate: &ast::Impl) {
502 let Some(wc) = delegate.where_clause() else {
503 return;
504 };
505 let (Some(trait_ty), Some(self_ty)) = (delegate.trait_(), delegate.self_ty()) else {
506 return;
507 };
508
509 let live_generics = [&trait_ty, &self_ty]
510 .into_iter()
511 .flat_map(|ty| ty.generic_arg_list())
512 .flat_map(|gal| gal.generic_args())
513 .map(|x| x.to_string())
514 .collect::<FxHashSet<_>>();
515
516 let has_no_live_generics = |pred: &WherePred| {
519 pred.syntax()
520 .descendants_with_tokens()
521 .filter_map(|e| e.into_token())
522 .any(|e| e.kind() == SyntaxKind::IDENT && live_generics.contains(&e.to_string()))
523 .not()
524 };
525
526 let predicates_to_remove: Vec<_> = wc.predicates().filter(has_no_live_generics).collect();
527 let remaining_predicates = wc.predicates().count() - predicates_to_remove.len();
528
529 if remaining_predicates == 0 {
530 editor.delete(wc.syntax().clone());
532 } else {
533 for pred in predicates_to_remove {
535 if let Some(previous) = pred.syntax().prev_sibling() {
537 if let Some(start) = previous.next_sibling_or_token() {
539 let end: SyntaxElement = pred.syntax().clone().into();
540 editor.delete_all(start..=end);
541 }
542 } else if let Some(next) = pred.syntax().next_sibling() {
543 if let Some(end) = next.prev_sibling_or_token() {
545 let start: SyntaxElement = pred.syntax().clone().into();
546 editor.delete_all(start..=end);
547 }
548 } else {
549 editor.delete(pred.syntax().clone());
550 }
551 }
552 }
553}
554
555fn finalize_delegate(
559 make: &SyntaxFactory,
560 delegate: &ast::Impl,
561 assoc_items: Option<Vec<ast::AssocItem>>,
562 remove_where_clauses: bool,
563) -> Option<ast::Impl> {
564 let has_items = assoc_items.as_ref().is_some_and(|items| !items.is_empty());
565
566 if !has_items && !remove_where_clauses {
567 return Some(delegate.clone());
568 }
569
570 let (editor, delegate) = SyntaxEditor::with_ast_node(delegate);
571
572 if let Some(items) = assoc_items
574 && !items.is_empty()
575 {
576 let new_assoc_item_list = make.assoc_item_list(items);
577 if let Some(old_list) = delegate.assoc_item_list() {
578 editor.replace(old_list.syntax(), new_assoc_item_list.syntax());
579 }
580 }
581
582 if remove_where_clauses {
584 remove_useless_where_clauses(&editor, &delegate);
585 }
586
587 ast::Impl::cast(editor.finish().new_root().clone())
588}
589
590fn generate_args_for_impl(
597 make: &SyntaxFactory,
598 old_impl_gpl: Option<GenericParamList>,
599 self_ty: &ast::Type,
600 field_ty: &ast::Type,
601 trait_params: Option<GenericParamList>,
602 old_trait_args: &FxHashSet<String>,
603) -> (Option<ast::GenericArgList>, Option<GenericParamList>) {
604 let Some(old_impl_args) = old_impl_gpl.map(|gpl| gpl.to_generic_args(make).generic_args())
605 else {
606 return (None, trait_params);
607 };
608
609 let mut arg_substs = FxHashMap::default();
612
613 if let field_ty @ ast::Type::PathType(_) = field_ty {
614 let field_args = field_ty.generic_arg_list().map(|gal| gal.generic_args());
615 let self_ty_args = self_ty.generic_arg_list().map(|gal| gal.generic_args());
616 if let (Some(field_args), Some(self_ty_args)) = (field_args, self_ty_args) {
617 self_ty_args.zip(field_args).for_each(|(self_ty_arg, field_arg)| {
618 arg_substs.entry(self_ty_arg.to_string()).or_insert(field_arg);
619 })
620 }
621 }
622
623 let mut params_to_remove = FxHashSet::default();
624
625 let args = old_impl_args
626 .map(|old_arg| {
627 arg_substs.get(&old_arg.to_string()).map_or_else(
628 || old_arg.clone(),
629 |replace_with| {
630 if trait_params.is_some() && old_trait_args.contains(&old_arg.to_string()) {
632 params_to_remove.insert(old_arg.to_string());
633 }
634 replace_with.clone()
635 },
636 )
637 })
638 .collect_vec();
639
640 let make = SyntaxFactory::without_mappings();
641 let result = args.is_empty().not().then(|| make.generic_arg_list(args, false));
642 let trait_params = trait_params.and_then(|gpl| filter_generic_params(gpl, ¶ms_to_remove));
643 (result, trait_params)
644}
645
646fn rename_strukt_args<N>(
647 ctx: &AssistContext<'_, '_>,
648 strukt: &ast::Struct,
649 item: &N,
650 args: &GenericArgList,
651) -> Option<N>
652where
653 N: ast::AstNode,
654{
655 let hir_strukt = ctx.sema.to_struct_def(strukt)?;
656 let hir_adt = hir::Adt::from(hir_strukt);
657 let scope = ctx.sema.scope(item.syntax())?;
658
659 let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone());
660 N::cast(transform.apply(item.syntax()))
661}
662
663fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_, '_>) -> bool {
664 ctx.sema
665 .source(trait_)
666 .and_then(|src| {
667 src.value
668 .syntax()
669 .descendants_with_tokens()
670 .filter_map(|e| e.into_token())
671 .find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW)
672 })
673 .is_some()
674}
675
676fn resolve_name_conflicts(
677 strukt_params: Option<ast::GenericParamList>,
678 old_impl_params: &Option<ast::GenericParamList>,
679) -> Option<ast::GenericParamList> {
680 let make = SyntaxFactory::without_mappings();
681 match (strukt_params, old_impl_params) {
682 (Some(old_strukt_params), Some(old_impl_params)) => {
683 let mut new_params: Vec<ast::GenericParam> = Vec::new();
684
685 for old_strukt_param in old_strukt_params.generic_params() {
686 let name = SmolStr::from(generic_param_name(&old_strukt_param)?);
688
689 let param_list_to_names = |param_list: &GenericParamList| {
691 param_list.generic_params().flat_map(|param| match param {
692 ast::GenericParam::TypeParam(t) => t.name().map(|name| name.to_string()),
693 p => Some(p.to_string()),
694 })
695 };
696 let new_params_list = make.generic_param_list(new_params.clone());
697 let existing_names = param_list_to_names(old_impl_params)
698 .chain(param_list_to_names(&new_params_list))
699 .collect_vec();
700 let mut name_generator = suggest_name::NameGenerator::new_with_names(
701 existing_names.iter().map(|s| s.as_str()),
702 );
703 let name = name_generator.suggest_name(&name);
704 match old_strukt_param {
705 ast::GenericParam::ConstParam(c) => {
706 if let Some(const_ty) = c.ty() {
707 let const_param = make.const_param(make.name(&name), const_ty);
708 new_params.push(ast::GenericParam::ConstParam(const_param));
709 }
710 }
711 p @ ast::GenericParam::LifetimeParam(_) => {
712 new_params.push(p);
713 }
714 ast::GenericParam::TypeParam(t) => {
715 let type_bounds = t.type_bound_list();
716 let type_param = make.type_param(make.name(&name), type_bounds);
717 new_params.push(ast::GenericParam::TypeParam(type_param));
718 }
719 }
720 }
721 Some(make.generic_param_list(new_params))
722 }
723 (Some(old_strukt_gpl), None) => Some(old_strukt_gpl),
724 _ => None,
725 }
726}
727
728fn process_assoc_item(
729 item: syntax::ast::AssocItem,
730 qual_path_ty: ast::Path,
731 base_name: &str,
732) -> Option<ast::AssocItem> {
733 match item {
734 AssocItem::Const(c) => const_assoc_item(c, qual_path_ty),
735 AssocItem::Fn(f) => func_assoc_item(f, qual_path_ty, base_name),
736 AssocItem::MacroCall(_) => {
737 None
740 }
741 AssocItem::TypeAlias(ta) => ty_assoc_item(ta, qual_path_ty),
742 }
743}
744
745fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option<AssocItem> {
746 let make = SyntaxFactory::without_mappings();
747 let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
748
749 let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
756 let inner = make.item_const(
757 item.attrs(),
758 item.visibility(),
759 item.name()?,
760 item.ty()?,
761 make.expr_path(qualified_path),
762 );
763
764 Some(AssocItem::Const(inner))
765}
766
767fn func_assoc_item(
768 item: syntax::ast::Fn,
769 qual_path_ty: Path,
770 base_name: &str,
771) -> Option<AssocItem> {
772 let make = SyntaxFactory::without_mappings();
773 let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
774 let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
775
776 let call = match item.param_list() {
777 Some(l) => match l.self_param() {
780 Some(slf) => {
781 let self_kw = make.expr_path(make.path_from_text("self"));
782 let self_kw = make.expr_field(self_kw, base_name).into();
783
784 let tail_expr_self = match slf.kind() {
785 ast::SelfParamKind::Owned => self_kw,
786 ast::SelfParamKind::Ref => make.expr_ref(self_kw, false),
787 ast::SelfParamKind::MutRef => make.expr_ref(self_kw, true),
788 };
789
790 let other_args = convert_param_list_to_arg_list(l, &make);
792 let all_args: Vec<ast::Expr> =
793 std::iter::once(tail_expr_self).chain(other_args.args()).collect();
794 let args = make.arg_list(all_args);
795
796 make.expr_call(make.expr_path(qualified_path), args).into()
797 }
798 None => make
799 .expr_call(make.expr_path(qualified_path), convert_param_list_to_arg_list(l, &make))
800 .into(),
801 },
802 None => make
803 .expr_call(
804 make.expr_path(qualified_path),
805 convert_param_list_to_arg_list(make.param_list(None, Vec::new()), &make),
806 )
807 .into(),
808 };
809
810 let body = make.block_expr(vec![], Some(call));
811 let func = make.fn_(
812 item.attrs(),
813 item.visibility(),
814 item.name()?,
815 item.generic_param_list(),
816 item.where_clause(),
817 item.param_list()?,
818 body,
819 item.ret_type(),
820 item.async_token().is_some(),
821 item.const_token().is_some(),
822 item.unsafe_token().is_some(),
823 item.gen_token().is_some(),
824 );
825
826 Some(AssocItem::Fn(func.indent(edit::IndentLevel(1))))
827}
828
829fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<AssocItem> {
830 let make = SyntaxFactory::without_mappings();
831 let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
832 let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
833 let ty = make.ty_path(qualified_path).into();
834 let ident = item.name()?.to_string();
835
836 let alias = make
837 .ty_alias(
838 item.attrs(),
839 ident.as_str(),
840 item.generic_param_list(),
841 None,
842 item.where_clause(),
843 Some((ty, None)),
844 )
845 .indent(edit::IndentLevel(1));
846
847 Some(AssocItem::TypeAlias(alias))
848}
849
850#[cfg(test)]
851mod test {
852
853 use super::*;
854 use crate::tests::{
855 check_assist, check_assist_not_applicable, check_assist_not_applicable_no_grouping,
856 };
857
858 #[test]
859 fn test_tuple_struct_basic() {
860 check_assist(
861 generate_delegate_trait,
862 r#"
863struct Base;
864struct S(B$0ase);
865trait Trait {}
866impl Trait for Base {}
867"#,
868 r#"
869struct Base;
870struct S(Base);
871
872impl Trait for S {}
873trait Trait {}
874impl Trait for Base {}
875"#,
876 );
877 }
878
879 #[test]
880 fn test_self_ty() {
881 check_assist_not_applicable(
886 generate_delegate_trait,
887 r#"
888struct Base(());
889struct S(B$0ase);
890trait Trait {
891 fn f() -> Self;
892}
893impl Trait for Base {
894 fn f() -> Base {
895 Base(())
896 }
897}
898"#,
899 );
900 }
901
902 #[test]
903 fn test_struct_struct_basic() {
904 check_assist(
905 generate_delegate_trait,
906 r#"
907struct Base;
908struct S {
909 ba$0se : Base
910}
911trait Trait {}
912impl Trait for Base {}
913"#,
914 r#"
915struct Base;
916struct S {
917 base : Base
918}
919
920impl Trait for S {}
921trait Trait {}
922impl Trait for Base {}
923"#,
924 )
925 }
926
927 #[test]
931 fn test_yet_empty_struct() {
932 check_assist_not_applicable(
933 generate_delegate_trait,
934 r#"
935struct Base;
936struct S {
937 $0
938}
939
940impl Trait for S {}
941trait Trait {}
942impl Trait for Base {}
943"#,
944 )
945 }
946
947 #[test]
948 fn test_yet_unspecified_field_type() {
949 check_assist_not_applicable(
950 generate_delegate_trait,
951 r#"
952struct Base;
953struct S {
954 ab$0c
955}
956
957impl Trait for S {}
958trait Trait {}
959impl Trait for Base {}
960"#,
961 );
962 }
963
964 #[test]
965 fn test_unsafe_trait() {
966 check_assist(
967 generate_delegate_trait,
968 r#"
969struct Base;
970struct S {
971 ba$0se : Base
972}
973unsafe trait Trait {}
974unsafe impl Trait for Base {}
975"#,
976 r#"
977struct Base;
978struct S {
979 base : Base
980}
981
982unsafe impl Trait for S {}
983unsafe trait Trait {}
984unsafe impl Trait for Base {}
985"#,
986 );
987 }
988
989 #[test]
990 fn test_unsafe_trait_with_unsafe_fn() {
991 check_assist(
992 generate_delegate_trait,
993 r#"
994struct Base;
995struct S {
996 ba$0se: Base,
997}
998
999unsafe trait Trait {
1000 unsafe fn a_func();
1001 unsafe fn a_method(&self);
1002}
1003unsafe impl Trait for Base {
1004 unsafe fn a_func() {}
1005 unsafe fn a_method(&self) {}
1006}
1007"#,
1008 r#"
1009struct Base;
1010struct S {
1011 base: Base,
1012}
1013
1014unsafe impl Trait for S {
1015 unsafe fn a_func() {
1016 <Base as Trait>::a_func()
1017 }
1018
1019 unsafe fn a_method(&self) {
1020 <Base as Trait>::a_method(&self.base)
1021 }
1022}
1023
1024unsafe trait Trait {
1025 unsafe fn a_func();
1026 unsafe fn a_method(&self);
1027}
1028unsafe impl Trait for Base {
1029 unsafe fn a_func() {}
1030 unsafe fn a_method(&self) {}
1031}
1032"#,
1033 );
1034 }
1035
1036 #[test]
1037 fn test_struct_with_where_clause() {
1038 check_assist(
1039 generate_delegate_trait,
1040 r#"
1041trait AnotherTrait {}
1042struct S<T>
1043where
1044 T: AnotherTrait,
1045{
1046 b$0 : T,
1047}"#,
1048 r#"
1049trait AnotherTrait {}
1050struct S<T>
1051where
1052 T: AnotherTrait,
1053{
1054 b : T,
1055}
1056
1057impl<T> AnotherTrait for S<T>
1058where
1059 T: AnotherTrait,
1060{
1061}"#,
1062 );
1063 }
1064
1065 #[test]
1066 fn test_fields_with_generics() {
1067 check_assist(
1068 generate_delegate_trait,
1069 r#"
1070struct B<T> {
1071 a: T
1072}
1073
1074trait Trait<T> {
1075 fn f(&self, a: T) -> T;
1076}
1077
1078impl<T1, T2> Trait<T1> for B<T2> {
1079 fn f(&self, a: T1) -> T1 { a }
1080}
1081
1082struct A {}
1083struct S {
1084 b :$0 B<A>,
1085}
1086"#,
1087 r#"
1088struct B<T> {
1089 a: T
1090}
1091
1092trait Trait<T> {
1093 fn f(&self, a: T) -> T;
1094}
1095
1096impl<T1, T2> Trait<T1> for B<T2> {
1097 fn f(&self, a: T1) -> T1 { a }
1098}
1099
1100struct A {}
1101struct S {
1102 b : B<A>,
1103}
1104
1105impl<T1> Trait<T1> for S {
1106 fn f(&self, a: T1) -> T1 {
1107 <B<A> as Trait<T1>>::f(&self.b, a)
1108 }
1109}
1110"#,
1111 );
1112 }
1113
1114 #[test]
1115 fn test_generics_with_conflict_names() {
1116 check_assist(
1117 generate_delegate_trait,
1118 r#"
1119struct B<T> {
1120 a: T
1121}
1122
1123trait Trait<T> {
1124 fn f(&self, a: T) -> T;
1125}
1126
1127impl<T, T0> Trait<T> for B<T0> {
1128 fn f(&self, a: T) -> T { a }
1129}
1130
1131struct S<T> {
1132 b : $0B<T>,
1133}
1134"#,
1135 r#"
1136struct B<T> {
1137 a: T
1138}
1139
1140trait Trait<T> {
1141 fn f(&self, a: T) -> T;
1142}
1143
1144impl<T, T0> Trait<T> for B<T0> {
1145 fn f(&self, a: T) -> T { a }
1146}
1147
1148struct S<T> {
1149 b : B<T>,
1150}
1151
1152impl<T, T1> Trait<T> for S<T1> {
1153 fn f(&self, a: T) -> T {
1154 <B<T1> as Trait<T>>::f(&self.b, a)
1155 }
1156}
1157"#,
1158 );
1159 }
1160
1161 #[test]
1162 fn test_lifetime_with_conflict_names() {
1163 check_assist(
1164 generate_delegate_trait,
1165 r#"
1166struct B<'a, T> {
1167 a: &'a T
1168}
1169
1170trait Trait<T> {
1171 fn f(&self, a: T) -> T;
1172}
1173
1174impl<'a, T, T0> Trait<T> for B<'a, T0> {
1175 fn f(&self, a: T) -> T { a }
1176}
1177
1178struct S<'a, T> {
1179 b : $0B<'a, T>,
1180}
1181"#,
1182 r#"
1183struct B<'a, T> {
1184 a: &'a T
1185}
1186
1187trait Trait<T> {
1188 fn f(&self, a: T) -> T;
1189}
1190
1191impl<'a, T, T0> Trait<T> for B<'a, T0> {
1192 fn f(&self, a: T) -> T { a }
1193}
1194
1195struct S<'a, T> {
1196 b : B<'a, T>,
1197}
1198
1199impl<'a, T, T1> Trait<T> for S<'a, T1> {
1200 fn f(&self, a: T) -> T {
1201 <B<'a, T1> as Trait<T>>::f(&self.b, a)
1202 }
1203}
1204"#,
1205 );
1206 }
1207
1208 #[test]
1209 fn test_multiple_generics() {
1210 check_assist(
1211 generate_delegate_trait,
1212 r#"
1213struct B<T1, T2> {
1214 a: T1,
1215 b: T2
1216}
1217
1218trait Trait<T> {
1219 fn f(&self, a: T) -> T;
1220}
1221
1222impl<T, T0> Trait<T> for B<T, T0> {
1223 fn f(&self, a: T) -> T { a }
1224}
1225
1226struct S<T> {
1227 b :$0 B<i32, T>,
1228}
1229"#,
1230 r#"
1231struct B<T1, T2> {
1232 a: T1,
1233 b: T2
1234}
1235
1236trait Trait<T> {
1237 fn f(&self, a: T) -> T;
1238}
1239
1240impl<T, T0> Trait<T> for B<T, T0> {
1241 fn f(&self, a: T) -> T { a }
1242}
1243
1244struct S<T> {
1245 b : B<i32, T>,
1246}
1247
1248impl<T1> Trait<i32> for S<T1> {
1249 fn f(&self, a: i32) -> i32 {
1250 <B<i32, T1> as Trait<i32>>::f(&self.b, a)
1251 }
1252}
1253"#,
1254 );
1255 }
1256
1257 #[test]
1258 fn test_generics_multiplex() {
1259 check_assist(
1260 generate_delegate_trait,
1261 r#"
1262struct B<T> {
1263 a: T
1264}
1265
1266trait Trait<T> {
1267 fn f(&self, a: T) -> T;
1268}
1269
1270impl<T> Trait<T> for B<T> {
1271 fn f(&self, a: T) -> T { a }
1272}
1273
1274struct S<T> {
1275 b : $0B<T>,
1276}
1277"#,
1278 r#"
1279struct B<T> {
1280 a: T
1281}
1282
1283trait Trait<T> {
1284 fn f(&self, a: T) -> T;
1285}
1286
1287impl<T> Trait<T> for B<T> {
1288 fn f(&self, a: T) -> T { a }
1289}
1290
1291struct S<T> {
1292 b : B<T>,
1293}
1294
1295impl<T1> Trait<T1> for S<T1> {
1296 fn f(&self, a: T1) -> T1 {
1297 <B<T1> as Trait<T1>>::f(&self.b, a)
1298 }
1299}
1300"#,
1301 );
1302 }
1303
1304 #[test]
1305 fn test_complex_without_where() {
1306 check_assist(
1307 generate_delegate_trait,
1308 r#"
1309trait Trait<'a, T, const C: usize> {
1310 type AssocType;
1311 const AssocConst: usize;
1312 fn assoc_fn(p: ());
1313 fn assoc_method(&self, p: ());
1314}
1315
1316struct Base;
1317struct S {
1318 field$0: Base
1319}
1320
1321impl<'a, T, const C: usize> Trait<'a, T, C> for Base {
1322 type AssocType = ();
1323 const AssocConst: usize = 0;
1324 fn assoc_fn(p: ()) {}
1325 fn assoc_method(&self, p: ()) {}
1326}
1327"#,
1328 r#"
1329trait Trait<'a, T, const C: usize> {
1330 type AssocType;
1331 const AssocConst: usize;
1332 fn assoc_fn(p: ());
1333 fn assoc_method(&self, p: ());
1334}
1335
1336struct Base;
1337struct S {
1338 field: Base
1339}
1340
1341impl<'a, T, const C: usize> Trait<'a, T, C> for S {
1342 type AssocType = <Base as Trait<'a, T, C>>::AssocType;
1343
1344 const AssocConst: usize = <Base as Trait<'a, T, C>>::AssocConst;
1345
1346 fn assoc_fn(p: ()) {
1347 <Base as Trait<'a, T, C>>::assoc_fn(p)
1348 }
1349
1350 fn assoc_method(&self, p: ()) {
1351 <Base as Trait<'a, T, C>>::assoc_method(&self.field, p)
1352 }
1353}
1354
1355impl<'a, T, const C: usize> Trait<'a, T, C> for Base {
1356 type AssocType = ();
1357 const AssocConst: usize = 0;
1358 fn assoc_fn(p: ()) {}
1359 fn assoc_method(&self, p: ()) {}
1360}
1361"#,
1362 );
1363 }
1364
1365 #[test]
1366 fn test_complex_two() {
1367 check_assist(
1368 generate_delegate_trait,
1369 r"
1370trait AnotherTrait {}
1371
1372trait Trait<'a, T, const C: usize> {
1373 type AssocType;
1374 const AssocConst: usize;
1375 fn assoc_fn(p: ());
1376 fn assoc_method(&self, p: ());
1377}
1378
1379struct Base;
1380struct S {
1381 fi$0eld: Base,
1382}
1383
1384impl<'b, C, const D: usize> Trait<'b, C, D> for Base
1385where
1386 C: AnotherTrait,
1387{
1388 type AssocType = ();
1389 const AssocConst: usize = 0;
1390 fn assoc_fn(p: ()) {}
1391 fn assoc_method(&self, p: ()) {}
1392}",
1393 r#"
1394trait AnotherTrait {}
1395
1396trait Trait<'a, T, const C: usize> {
1397 type AssocType;
1398 const AssocConst: usize;
1399 fn assoc_fn(p: ());
1400 fn assoc_method(&self, p: ());
1401}
1402
1403struct Base;
1404struct S {
1405 field: Base,
1406}
1407
1408impl<'b, C, const D: usize> Trait<'b, C, D> for S
1409where
1410 C: AnotherTrait,
1411{
1412 type AssocType = <Base as Trait<'b, C, D>>::AssocType;
1413
1414 const AssocConst: usize = <Base as Trait<'b, C, D>>::AssocConst;
1415
1416 fn assoc_fn(p: ()) {
1417 <Base as Trait<'b, C, D>>::assoc_fn(p)
1418 }
1419
1420 fn assoc_method(&self, p: ()) {
1421 <Base as Trait<'b, C, D>>::assoc_method(&self.field, p)
1422 }
1423}
1424
1425impl<'b, C, const D: usize> Trait<'b, C, D> for Base
1426where
1427 C: AnotherTrait,
1428{
1429 type AssocType = ();
1430 const AssocConst: usize = 0;
1431 fn assoc_fn(p: ()) {}
1432 fn assoc_method(&self, p: ()) {}
1433}"#,
1434 )
1435 }
1436
1437 #[test]
1438 fn test_complex_three() {
1439 check_assist(
1440 generate_delegate_trait,
1441 r#"
1442trait AnotherTrait {}
1443trait YetAnotherTrait {}
1444
1445struct StructImplsAll();
1446impl AnotherTrait for StructImplsAll {}
1447impl YetAnotherTrait for StructImplsAll {}
1448
1449trait Trait<'a, T, const C: usize> {
1450 type A;
1451 const ASSOC_CONST: usize = C;
1452 fn assoc_fn(p: ());
1453 fn assoc_method(&self, p: ());
1454}
1455
1456struct Base;
1457struct S {
1458 fi$0eld: Base,
1459}
1460
1461impl<'b, A: AnotherTrait + YetAnotherTrait, const B: usize> Trait<'b, A, B> for Base
1462where
1463 A: AnotherTrait,
1464{
1465 type A = i32;
1466
1467 const ASSOC_CONST: usize = B;
1468
1469 fn assoc_fn(p: ()) {}
1470
1471 fn assoc_method(&self, p: ()) {}
1472}
1473"#,
1474 r#"
1475trait AnotherTrait {}
1476trait YetAnotherTrait {}
1477
1478struct StructImplsAll();
1479impl AnotherTrait for StructImplsAll {}
1480impl YetAnotherTrait for StructImplsAll {}
1481
1482trait Trait<'a, T, const C: usize> {
1483 type A;
1484 const ASSOC_CONST: usize = C;
1485 fn assoc_fn(p: ());
1486 fn assoc_method(&self, p: ());
1487}
1488
1489struct Base;
1490struct S {
1491 field: Base,
1492}
1493
1494impl<'b, A: AnotherTrait + YetAnotherTrait, const B: usize> Trait<'b, A, B> for S
1495where
1496 A: AnotherTrait,
1497{
1498 type A = <Base as Trait<'b, A, B>>::A;
1499
1500 const ASSOC_CONST: usize = <Base as Trait<'b, A, B>>::ASSOC_CONST;
1501
1502 fn assoc_fn(p: ()) {
1503 <Base as Trait<'b, A, B>>::assoc_fn(p)
1504 }
1505
1506 fn assoc_method(&self, p: ()) {
1507 <Base as Trait<'b, A, B>>::assoc_method(&self.field, p)
1508 }
1509}
1510
1511impl<'b, A: AnotherTrait + YetAnotherTrait, const B: usize> Trait<'b, A, B> for Base
1512where
1513 A: AnotherTrait,
1514{
1515 type A = i32;
1516
1517 const ASSOC_CONST: usize = B;
1518
1519 fn assoc_fn(p: ()) {}
1520
1521 fn assoc_method(&self, p: ()) {}
1522}
1523"#,
1524 )
1525 }
1526
1527 #[test]
1528 fn test_type_bound() {
1529 check_assist(
1530 generate_delegate_trait,
1531 r#"
1532trait AnotherTrait {}
1533struct S<T>
1534where
1535 T: AnotherTrait,
1536{
1537 b$0: T,
1538}"#,
1539 r#"
1540trait AnotherTrait {}
1541struct S<T>
1542where
1543 T: AnotherTrait,
1544{
1545 b: T,
1546}
1547
1548impl<T> AnotherTrait for S<T>
1549where
1550 T: AnotherTrait,
1551{
1552}"#,
1553 );
1554 }
1555
1556 #[test]
1557 fn test_type_bound_with_generics_1() {
1558 check_assist(
1559 generate_delegate_trait,
1560 r#"
1561trait AnotherTrait {}
1562struct B<T, T1>
1563where
1564 T1: AnotherTrait
1565{
1566 a: T,
1567 b: T1
1568}
1569
1570trait Trait<T> {
1571 fn f(&self, a: T) -> T;
1572}
1573
1574impl<T, T0, T1: AnotherTrait> Trait<T> for B<T0, T1> {
1575 fn f(&self, a: T) -> T { a }
1576}
1577
1578struct S<T, T1>
1579where
1580 T1: AnotherTrait
1581{
1582 b : $0B<T, T1>,
1583}"#,
1584 r#"
1585trait AnotherTrait {}
1586struct B<T, T1>
1587where
1588 T1: AnotherTrait
1589{
1590 a: T,
1591 b: T1
1592}
1593
1594trait Trait<T> {
1595 fn f(&self, a: T) -> T;
1596}
1597
1598impl<T, T0, T1: AnotherTrait> Trait<T> for B<T0, T1> {
1599 fn f(&self, a: T) -> T { a }
1600}
1601
1602struct S<T, T1>
1603where
1604 T1: AnotherTrait
1605{
1606 b : B<T, T1>,
1607}
1608
1609impl<T, T2, T3> Trait<T> for S<T2, T3>
1610where
1611 T3: AnotherTrait
1612{
1613 fn f(&self, a: T) -> T {
1614 <B<T2, T3> as Trait<T>>::f(&self.b, a)
1615 }
1616}"#,
1617 );
1618 }
1619
1620 #[test]
1621 fn test_type_bound_with_generics_2() {
1622 check_assist(
1623 generate_delegate_trait,
1624 r#"
1625trait AnotherTrait {}
1626struct B<T1>
1627where
1628 T1: AnotherTrait
1629{
1630 b: T1
1631}
1632
1633trait Trait<T1> {
1634 fn f(&self, a: T1) -> T1;
1635}
1636
1637impl<T, T1: AnotherTrait> Trait<T> for B<T1> {
1638 fn f(&self, a: T) -> T { a }
1639}
1640
1641struct S<T>
1642where
1643 T: AnotherTrait
1644{
1645 b : $0B<T>,
1646}"#,
1647 r#"
1648trait AnotherTrait {}
1649struct B<T1>
1650where
1651 T1: AnotherTrait
1652{
1653 b: T1
1654}
1655
1656trait Trait<T1> {
1657 fn f(&self, a: T1) -> T1;
1658}
1659
1660impl<T, T1: AnotherTrait> Trait<T> for B<T1> {
1661 fn f(&self, a: T) -> T { a }
1662}
1663
1664struct S<T>
1665where
1666 T: AnotherTrait
1667{
1668 b : B<T>,
1669}
1670
1671impl<T, T2> Trait<T> for S<T2>
1672where
1673 T2: AnotherTrait
1674{
1675 fn f(&self, a: T) -> T {
1676 <B<T2> as Trait<T>>::f(&self.b, a)
1677 }
1678}"#,
1679 );
1680 }
1681
1682 #[test]
1683 fn test_docstring_example() {
1684 check_assist(
1685 generate_delegate_trait,
1686 r#"
1687trait SomeTrait {
1688 type T;
1689 fn fn_(arg: u32) -> u32;
1690 fn method_(&mut self) -> bool;
1691}
1692struct A;
1693impl SomeTrait for A {
1694 type T = u32;
1695 fn fn_(arg: u32) -> u32 {
1696 42
1697 }
1698 fn method_(&mut self) -> bool {
1699 false
1700 }
1701}
1702struct B {
1703 a$0: A,
1704}
1705"#,
1706 r#"
1707trait SomeTrait {
1708 type T;
1709 fn fn_(arg: u32) -> u32;
1710 fn method_(&mut self) -> bool;
1711}
1712struct A;
1713impl SomeTrait for A {
1714 type T = u32;
1715 fn fn_(arg: u32) -> u32 {
1716 42
1717 }
1718 fn method_(&mut self) -> bool {
1719 false
1720 }
1721}
1722struct B {
1723 a: A,
1724}
1725
1726impl SomeTrait for B {
1727 type T = <A as SomeTrait>::T;
1728
1729 fn fn_(arg: u32) -> u32 {
1730 <A as SomeTrait>::fn_(arg)
1731 }
1732
1733 fn method_(&mut self) -> bool {
1734 <A as SomeTrait>::method_(&mut self.a)
1735 }
1736}
1737"#,
1738 );
1739 }
1740
1741 #[test]
1742 fn import_from_other_mod() {
1743 check_assist(
1744 generate_delegate_trait,
1745 r#"
1746mod some_module {
1747 pub trait SomeTrait {
1748 type T;
1749 fn fn_(arg: u32) -> u32;
1750 fn method_(&mut self) -> bool;
1751 }
1752 pub struct A;
1753 impl SomeTrait for A {
1754 type T = u32;
1755
1756 fn fn_(arg: u32) -> u32 {
1757 42
1758 }
1759
1760 fn method_(&mut self) -> bool {
1761 false
1762 }
1763 }
1764}
1765
1766struct B {
1767 a$0: some_module::A,
1768}"#,
1769 r#"
1770mod some_module {
1771 pub trait SomeTrait {
1772 type T;
1773 fn fn_(arg: u32) -> u32;
1774 fn method_(&mut self) -> bool;
1775 }
1776 pub struct A;
1777 impl SomeTrait for A {
1778 type T = u32;
1779
1780 fn fn_(arg: u32) -> u32 {
1781 42
1782 }
1783
1784 fn method_(&mut self) -> bool {
1785 false
1786 }
1787 }
1788}
1789
1790struct B {
1791 a: some_module::A,
1792}
1793
1794impl some_module::SomeTrait for B {
1795 type T = <some_module::A as some_module::SomeTrait>::T;
1796
1797 fn fn_(arg: u32) -> u32 {
1798 <some_module::A as some_module::SomeTrait>::fn_(arg)
1799 }
1800
1801 fn method_(&mut self) -> bool {
1802 <some_module::A as some_module::SomeTrait>::method_(&mut self.a)
1803 }
1804}"#,
1805 )
1806 }
1807
1808 #[test]
1809 fn test_fn_with_attrs() {
1810 check_assist(
1811 generate_delegate_trait,
1812 r#"
1813struct A;
1814
1815trait T {
1816 #[cfg(test)]
1817 fn f(&self, a: u32);
1818 #[cfg(not(test))]
1819 fn f(&self, a: bool);
1820}
1821
1822impl T for A {
1823 #[cfg(test)]
1824 fn f(&self, a: u32) {}
1825 #[cfg(not(test))]
1826 fn f(&self, a: bool) {}
1827}
1828
1829struct B {
1830 a$0: A,
1831}
1832"#,
1833 r#"
1834struct A;
1835
1836trait T {
1837 #[cfg(test)]
1838 fn f(&self, a: u32);
1839 #[cfg(not(test))]
1840 fn f(&self, a: bool);
1841}
1842
1843impl T for A {
1844 #[cfg(test)]
1845 fn f(&self, a: u32) {}
1846 #[cfg(not(test))]
1847 fn f(&self, a: bool) {}
1848}
1849
1850struct B {
1851 a: A,
1852}
1853
1854impl T for B {
1855 #[cfg(test)]
1856 fn f(&self, a: u32) {
1857 <A as T>::f(&self.a, a)
1858 }
1859
1860 #[cfg(not(test))]
1861 fn f(&self, a: bool) {
1862 <A as T>::f(&self.a, a)
1863 }
1864}
1865"#,
1866 );
1867 }
1868
1869 #[test]
1870 fn test_ty_alias_attrs() {
1871 check_assist(
1872 generate_delegate_trait,
1873 r#"
1874struct A;
1875
1876trait T {
1877 #[cfg(test)]
1878 type t;
1879 #[cfg(not(test))]
1880 type t;
1881}
1882
1883impl T for A {
1884 #[cfg(test)]
1885 type t = u32;
1886 #[cfg(not(test))]
1887 type t = bool;
1888}
1889
1890struct B {
1891 a$0: A,
1892}
1893"#,
1894 r#"
1895struct A;
1896
1897trait T {
1898 #[cfg(test)]
1899 type t;
1900 #[cfg(not(test))]
1901 type t;
1902}
1903
1904impl T for A {
1905 #[cfg(test)]
1906 type t = u32;
1907 #[cfg(not(test))]
1908 type t = bool;
1909}
1910
1911struct B {
1912 a: A,
1913}
1914
1915impl T for B {
1916 #[cfg(test)]
1917 type t = <A as T>::t;
1918
1919 #[cfg(not(test))]
1920 type t = <A as T>::t;
1921}
1922"#,
1923 );
1924 }
1925
1926 #[test]
1927 fn assoc_items_attributes_mutably_cloned() {
1928 check_assist(
1929 generate_delegate_trait,
1930 r#"
1931pub struct A;
1932pub trait C<D> {
1933 #[allow(clippy::dead_code)]
1934 fn a_funk(&self) -> &D;
1935}
1936
1937pub struct B<T: C<A>> {
1938 has_dr$0ain: T,
1939}
1940"#,
1941 r#"
1942pub struct A;
1943pub trait C<D> {
1944 #[allow(clippy::dead_code)]
1945 fn a_funk(&self) -> &D;
1946}
1947
1948pub struct B<T: C<A>> {
1949 has_drain: T,
1950}
1951
1952impl<D, T: C<A>> C<D> for B<T> {
1953 #[allow(clippy::dead_code)]
1954 fn a_funk(&self) -> &D {
1955 <T as C<D>>::a_funk(&self.has_drain)
1956 }
1957}
1958"#,
1959 )
1960 }
1961
1962 #[test]
1963 fn delegate_trait_skipped_when_no_grouping() {
1964 check_assist_not_applicable_no_grouping(
1965 generate_delegate_trait,
1966 r#"
1967trait SomeTrait {
1968 type T;
1969 fn fn_(arg: u32) -> u32;
1970 fn method_(&mut self) -> bool;
1971}
1972struct A;
1973impl SomeTrait for A {
1974 type T = u32;
1975
1976 fn fn_(arg: u32) -> u32 {
1977 42
1978 }
1979
1980 fn method_(&mut self) -> bool {
1981 false
1982 }
1983}
1984struct B {
1985 a$0 : A,
1986}
1987"#,
1988 );
1989 }
1990}