mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 05:08:52 +00:00
Resolve most of corner cases
This commit is contained in:
parent
fe3170dc34
commit
7259cc82f3
2 changed files with 124 additions and 12 deletions
|
@ -13,9 +13,6 @@ pub(crate) fn replace_impl_trait_with_generic(
|
|||
let type_param = type_impl_trait.syntax().parent().and_then(ast::Param::cast)?;
|
||||
let type_fn = type_param.syntax().ancestors().nth(2).and_then(ast::Fn::cast)?;
|
||||
|
||||
let generic_param_list =
|
||||
type_fn.generic_param_list().unwrap_or_else(|| make::generic_param_list(None));
|
||||
|
||||
let impl_trait_ty = type_impl_trait
|
||||
.syntax()
|
||||
.descendants()
|
||||
|
@ -31,11 +28,16 @@ pub(crate) fn replace_impl_trait_with_generic(
|
|||
target,
|
||||
|edit| {
|
||||
let generic_letter = impl_trait_ty[..1].to_string();
|
||||
edit.replace_ast::<ast::Type>(type_impl_trait.into(), make::ty(&generic_letter));
|
||||
|
||||
let new_params = generic_param_list
|
||||
.append_param(make::generic_param(generic_letter, Some(impl_trait_ty)));
|
||||
let new_type_fn = type_fn.replace_descendant(generic_param_list, new_params);
|
||||
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))
|
||||
.with_generic_params(generic_param_list);
|
||||
|
||||
edit.replace_ast(type_fn.clone(), new_type_fn);
|
||||
},
|
||||
)
|
||||
|
@ -48,7 +50,7 @@ mod tests {
|
|||
use crate::tests::check_assist;
|
||||
|
||||
#[test]
|
||||
fn replace_with_generic_params() {
|
||||
fn replace_impl_trait_with_generic_params() {
|
||||
check_assist(
|
||||
replace_impl_trait_with_generic,
|
||||
r#"
|
||||
|
@ -59,4 +61,96 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replace_impl_trait_without_generic_params() {
|
||||
check_assist(
|
||||
replace_impl_trait_with_generic,
|
||||
r#"
|
||||
fn foo(bar: <|>impl Bar) {}
|
||||
"#,
|
||||
r#"
|
||||
fn foo<B: Bar>(bar: B) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[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#"
|
||||
fn foo<G, B: Bar>(foo: impl Foo, bar: B) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replace_impl_trait_with_empty_generic_params() {
|
||||
check_assist(
|
||||
replace_impl_trait_with_generic,
|
||||
r#"
|
||||
fn foo<>(bar: <|>impl Bar) {}
|
||||
"#,
|
||||
r#"
|
||||
fn foo<B: Bar>(bar: B) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replace_impl_trait_with_empty_multiline_generic_params() {
|
||||
// FIXME: It would be more correct to place the generic parameter
|
||||
// on the next line after the left angle.
|
||||
check_assist(
|
||||
replace_impl_trait_with_generic,
|
||||
r#"
|
||||
fn foo<
|
||||
>(bar: <|>impl Bar) {}
|
||||
"#,
|
||||
r#"
|
||||
fn foo<B: Bar,
|
||||
>(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#"
|
||||
fn foo<B, C: Bar>(bar: C) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[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,
|
||||
H,
|
||||
B: Bar,
|
||||
>(bar: B) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
ast::{
|
||||
self,
|
||||
make::{self, tokens},
|
||||
AstNode, TypeBoundsOwner,
|
||||
AstNode, GenericParamsOwner, NameOwner, TypeBoundsOwner,
|
||||
},
|
||||
AstToken, Direction, InsertPosition, SmolStr, SyntaxElement, SyntaxKind,
|
||||
SyntaxKind::{ATTR, COMMENT, WHITESPACE},
|
||||
|
@ -46,6 +46,19 @@ impl ast::Fn {
|
|||
to_insert.push(body.syntax().clone().into());
|
||||
self.replace_children(single_node(old_body_or_semi), to_insert)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_generic_params(&self, generic_args: ast::GenericParamList) -> ast::Fn {
|
||||
if let Some(old) = self.generic_param_list() {
|
||||
return self.replace_descendant(old, generic_args);
|
||||
}
|
||||
|
||||
let anchor = self.name().expect("The function must have a name").syntax().clone();
|
||||
|
||||
let mut to_insert: ArrayVec<[SyntaxElement; 1]> = ArrayVec::new();
|
||||
to_insert.push(generic_args.syntax().clone().into());
|
||||
self.insert_children(InsertPosition::After(anchor.into()), to_insert)
|
||||
}
|
||||
}
|
||||
|
||||
fn make_multiline<N>(node: N) -> N
|
||||
|
@ -461,14 +474,17 @@ impl ast::MatchArmList {
|
|||
|
||||
impl ast::GenericParamList {
|
||||
#[must_use]
|
||||
pub fn append_params(&self, params: impl IntoIterator<Item = ast::GenericParam>) -> Self {
|
||||
pub fn append_params(
|
||||
&self,
|
||||
params: impl IntoIterator<Item = ast::GenericParam>,
|
||||
) -> ast::GenericParamList {
|
||||
let mut res = self.clone();
|
||||
params.into_iter().for_each(|it| res = res.append_param(it));
|
||||
res
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn append_param(&self, item: ast::GenericParam) -> Self {
|
||||
pub fn append_param(&self, item: ast::GenericParam) -> ast::GenericParamList {
|
||||
let is_multiline = self.syntax().text().contains_char('\n');
|
||||
let ws;
|
||||
let space = if is_multiline {
|
||||
|
@ -482,7 +498,9 @@ impl ast::GenericParamList {
|
|||
};
|
||||
|
||||
let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new();
|
||||
to_insert.push(space.into());
|
||||
if self.generic_params().next().is_some() {
|
||||
to_insert.push(space.into());
|
||||
}
|
||||
to_insert.push(item.syntax().clone().into());
|
||||
to_insert.push(make::token(T![,]).into());
|
||||
|
||||
|
|
Loading…
Reference in a new issue