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