2020-09-02 17:32:18 -05:00
|
|
|
use syntax::ast::{self, edit::AstNodeEdit, make, AstNode, GenericParamsOwner};
|
|
|
|
|
|
|
|
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
|
|
|
|
|
|
|
// Assist: replace_impl_trait_with_generic
|
|
|
|
//
|
|
|
|
// Replaces `impl Trait` function argument with the named generic.
|
2020-09-04 07:24:36 -05:00
|
|
|
//
|
|
|
|
// ```
|
2020-09-04 09:55:27 -05:00
|
|
|
// fn foo(bar: <|>impl Bar) {}
|
2020-09-04 07:24:36 -05:00
|
|
|
// ```
|
|
|
|
// ->
|
|
|
|
// ```
|
2020-09-04 14:58:50 -05:00
|
|
|
// fn foo<B: Bar>(bar: B) {}
|
2020-09-04 07:24:36 -05:00
|
|
|
// ```
|
2020-09-02 17:32:18 -05:00
|
|
|
pub(crate) fn replace_impl_trait_with_generic(
|
|
|
|
acc: &mut Assists,
|
|
|
|
ctx: &AssistContext,
|
|
|
|
) -> Option<()> {
|
|
|
|
let type_impl_trait = ctx.find_node_at_offset::<ast::ImplTraitType>()?;
|
|
|
|
let type_param = type_impl_trait.syntax().parent().and_then(ast::Param::cast)?;
|
2020-09-04 07:24:36 -05:00
|
|
|
let type_fn = type_param.syntax().ancestors().find_map(ast::Fn::cast)?;
|
2020-09-02 17:32:18 -05:00
|
|
|
|
2020-09-04 09:55:27 -05:00
|
|
|
let impl_trait_ty = type_impl_trait.type_bound_list()?;
|
2020-09-02 17:32:18 -05:00
|
|
|
|
|
|
|
let target = type_fn.syntax().text_range();
|
|
|
|
acc.add(
|
|
|
|
AssistId("replace_impl_trait_with_generic", AssistKind::RefactorRewrite),
|
|
|
|
"Replace impl trait with generic",
|
|
|
|
target,
|
|
|
|
|edit| {
|
2020-09-04 09:55:27 -05:00
|
|
|
let generic_letter = impl_trait_ty.to_string().chars().next().unwrap().to_string();
|
2020-09-02 17:32:18 -05:00
|
|
|
|
2020-09-03 06:46:28 -05:00
|
|
|
let generic_param_list = type_fn
|
|
|
|
.generic_param_list()
|
|
|
|
.unwrap_or_else(|| make::generic_param_list(None))
|
|
|
|
.append_param(make::generic_param(generic_letter.clone(), Some(impl_trait_ty)));
|
|
|
|
|
|
|
|
let new_type_fn = type_fn
|
|
|
|
.replace_descendant::<ast::Type>(type_impl_trait.into(), make::ty(&generic_letter))
|
2020-09-04 07:24:36 -05:00
|
|
|
.with_generic_param_list(generic_param_list);
|
2020-09-03 06:46:28 -05:00
|
|
|
|
2020-09-02 17:32:18 -05:00
|
|
|
edit.replace_ast(type_fn.clone(), new_type_fn);
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
use crate::tests::check_assist;
|
|
|
|
|
|
|
|
#[test]
|
2020-09-03 06:46:28 -05:00
|
|
|
fn replace_impl_trait_with_generic_params() {
|
2020-09-02 17:32:18 -05:00
|
|
|
check_assist(
|
|
|
|
replace_impl_trait_with_generic,
|
|
|
|
r#"
|
|
|
|
fn foo<G>(bar: <|>impl Bar) {}
|
|
|
|
"#,
|
|
|
|
r#"
|
2020-09-04 14:58:50 -05:00
|
|
|
fn foo<G, B: Bar>(bar: B) {}
|
2020-09-02 17:32:18 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
2020-09-03 06:46:28 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn replace_impl_trait_without_generic_params() {
|
|
|
|
check_assist(
|
|
|
|
replace_impl_trait_with_generic,
|
|
|
|
r#"
|
|
|
|
fn foo(bar: <|>impl Bar) {}
|
|
|
|
"#,
|
|
|
|
r#"
|
2020-09-04 14:58:50 -05:00
|
|
|
fn foo<B: Bar>(bar: B) {}
|
2020-09-03 06:46:28 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn replace_two_impl_trait_with_generic_params() {
|
|
|
|
check_assist(
|
|
|
|
replace_impl_trait_with_generic,
|
|
|
|
r#"
|
|
|
|
fn foo<G>(foo: impl Foo, bar: <|>impl Bar) {}
|
|
|
|
"#,
|
|
|
|
r#"
|
2020-09-04 14:58:50 -05:00
|
|
|
fn foo<G, B: Bar>(foo: impl Foo, bar: B) {}
|
2020-09-03 06:46:28 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn replace_impl_trait_with_empty_generic_params() {
|
|
|
|
check_assist(
|
|
|
|
replace_impl_trait_with_generic,
|
|
|
|
r#"
|
|
|
|
fn foo<>(bar: <|>impl Bar) {}
|
|
|
|
"#,
|
|
|
|
r#"
|
2020-09-04 14:58:50 -05:00
|
|
|
fn foo<B: Bar>(bar: B) {}
|
2020-09-03 06:46:28 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn replace_impl_trait_with_empty_multiline_generic_params() {
|
|
|
|
check_assist(
|
|
|
|
replace_impl_trait_with_generic,
|
|
|
|
r#"
|
|
|
|
fn foo<
|
|
|
|
>(bar: <|>impl Bar) {}
|
|
|
|
"#,
|
|
|
|
r#"
|
2020-09-04 14:58:50 -05:00
|
|
|
fn foo<B: Bar
|
2020-09-03 06:46:28 -05:00
|
|
|
>(bar: B) {}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[ignore = "This case is very rare but there is no simple solutions to fix it."]
|
|
|
|
fn replace_impl_trait_with_exist_generic_letter() {
|
|
|
|
check_assist(
|
|
|
|
replace_impl_trait_with_generic,
|
|
|
|
r#"
|
|
|
|
fn foo<B>(bar: <|>impl Bar) {}
|
|
|
|
"#,
|
|
|
|
r#"
|
2020-09-04 14:58:50 -05:00
|
|
|
fn foo<B, C: Bar>(bar: C) {}
|
2020-09-03 06:46:28 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn replace_impl_trait_with_multiline_generic_params() {
|
|
|
|
check_assist(
|
|
|
|
replace_impl_trait_with_generic,
|
|
|
|
r#"
|
|
|
|
fn foo<
|
|
|
|
G: Foo,
|
|
|
|
F,
|
|
|
|
H,
|
|
|
|
>(bar: <|>impl Bar) {}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn foo<
|
|
|
|
G: Foo,
|
|
|
|
F,
|
2020-09-04 14:58:50 -05:00
|
|
|
H, B: Bar
|
2020-09-03 06:46:28 -05:00
|
|
|
>(bar: B) {}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
2020-09-04 09:55:27 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn replace_impl_trait_multiple() {
|
|
|
|
check_assist(
|
|
|
|
replace_impl_trait_with_generic,
|
|
|
|
r#"
|
|
|
|
fn foo(bar: <|>impl Foo + Bar) {}
|
|
|
|
"#,
|
|
|
|
r#"
|
2020-09-04 14:58:50 -05:00
|
|
|
fn foo<F: Foo + Bar>(bar: F) {}
|
2020-09-04 09:55:27 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
2020-09-02 17:32:18 -05:00
|
|
|
}
|