2 ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode},
6 use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists};
8 // Assist: introduce_named_generic
10 // Replaces `impl Trait` function argument with the named generic.
13 // fn foo(bar: $0impl Bar) {}
17 // fn foo<B: Bar>(bar: B) {}
19 pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
20 let impl_trait_type = ctx.find_node_at_offset::<ast::ImplTraitType>()?;
21 let param = impl_trait_type.syntax().parent().and_then(ast::Param::cast)?;
22 let fn_ = param.syntax().ancestors().find_map(ast::Fn::cast)?;
24 let type_bound_list = impl_trait_type.type_bound_list()?;
26 let target = fn_.syntax().text_range();
28 AssistId("introduce_named_generic", AssistKind::RefactorRewrite),
29 "Replace impl trait with generic",
32 let impl_trait_type = edit.make_mut(impl_trait_type);
33 let fn_ = edit.make_mut(fn_);
35 let type_param_name = suggest_name::for_generic_parameter(&impl_trait_type);
37 let type_param = make::type_param(make::name(&type_param_name), Some(type_bound_list))
39 let new_ty = make::ty(&type_param_name).clone_for_update();
41 ted::replace(impl_trait_type.syntax(), new_ty.syntax());
42 fn_.get_or_create_generic_param_list().add_generic_param(type_param.into())
51 use crate::tests::check_assist;
54 fn introduce_named_generic_params() {
56 introduce_named_generic,
57 r#"fn foo<G>(bar: $0impl Bar) {}"#,
58 r#"fn foo<G, B: Bar>(bar: B) {}"#,
63 fn replace_impl_trait_without_generic_params() {
65 introduce_named_generic,
66 r#"fn foo(bar: $0impl Bar) {}"#,
67 r#"fn foo<B: Bar>(bar: B) {}"#,
72 fn replace_two_impl_trait_with_generic_params() {
74 introduce_named_generic,
75 r#"fn foo<G>(foo: impl Foo, bar: $0impl Bar) {}"#,
76 r#"fn foo<G, B: Bar>(foo: impl Foo, bar: B) {}"#,
81 fn replace_impl_trait_with_empty_generic_params() {
83 introduce_named_generic,
84 r#"fn foo<>(bar: $0impl Bar) {}"#,
85 r#"fn foo<B: Bar>(bar: B) {}"#,
90 fn replace_impl_trait_with_empty_multiline_generic_params() {
92 introduce_named_generic,
105 fn replace_impl_trait_with_exist_generic_letter() {
106 // FIXME: This is wrong, we should pick a different name if the one we
107 // want is already bound.
109 introduce_named_generic,
110 r#"fn foo<B>(bar: $0impl Bar) {}"#,
111 r#"fn foo<B, B: Bar>(bar: B) {}"#,
116 fn replace_impl_trait_with_multiline_generic_params() {
118 introduce_named_generic,
124 >(bar: $0impl Bar) {}
137 fn replace_impl_trait_multiple() {
139 introduce_named_generic,
140 r#"fn foo(bar: $0impl Foo + Bar) {}"#,
141 r#"fn foo<F: Foo + Bar>(bar: F) {}"#,