mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
fix: pick up new names when the name exists in 'introduce_named_generic'
This commit is contained in:
parent
34df29620a
commit
e8dc8ccc59
2 changed files with 45 additions and 32 deletions
|
@ -31,15 +31,16 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||||
|edit| {
|
|edit| {
|
||||||
let impl_trait_type = edit.make_mut(impl_trait_type);
|
let impl_trait_type = edit.make_mut(impl_trait_type);
|
||||||
let fn_ = edit.make_mut(fn_);
|
let fn_ = edit.make_mut(fn_);
|
||||||
|
let fn_generic_param_list = fn_.get_or_create_generic_param_list();
|
||||||
let type_param_name = suggest_name::for_generic_parameter(&impl_trait_type);
|
let type_param_name =
|
||||||
|
suggest_name::for_generic_parameter(&impl_trait_type, &fn_generic_param_list);
|
||||||
|
|
||||||
let type_param = make::type_param(make::name(&type_param_name), Some(type_bound_list))
|
let type_param = make::type_param(make::name(&type_param_name), Some(type_bound_list))
|
||||||
.clone_for_update();
|
.clone_for_update();
|
||||||
let new_ty = make::ty(&type_param_name).clone_for_update();
|
let new_ty = make::ty(&type_param_name).clone_for_update();
|
||||||
|
|
||||||
ted::replace(impl_trait_type.syntax(), new_ty.syntax());
|
ted::replace(impl_trait_type.syntax(), new_ty.syntax());
|
||||||
fn_.get_or_create_generic_param_list().add_generic_param(type_param.into());
|
fn_generic_param_list.add_generic_param(type_param.into());
|
||||||
|
|
||||||
if let Some(cap) = ctx.config.snippet_cap {
|
if let Some(cap) = ctx.config.snippet_cap {
|
||||||
if let Some(generic_param) =
|
if let Some(generic_param) =
|
||||||
|
@ -111,12 +112,19 @@ fn foo<$0B: Bar
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn replace_impl_trait_with_exist_generic_letter() {
|
fn replace_impl_trait_with_exist_generic_letter() {
|
||||||
// FIXME: This is wrong, we should pick a different name if the one we
|
|
||||||
// want is already bound.
|
|
||||||
check_assist(
|
check_assist(
|
||||||
introduce_named_generic,
|
introduce_named_generic,
|
||||||
r#"fn foo<B>(bar: $0impl Bar) {}"#,
|
r#"fn foo<B>(bar: $0impl Bar) {}"#,
|
||||||
r#"fn foo<B, $0B: Bar>(bar: B) {}"#,
|
r#"fn foo<B, $0B0: Bar>(bar: B0) {}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn replace_impl_trait_with_more_exist_generic_letter() {
|
||||||
|
check_assist(
|
||||||
|
introduce_named_generic,
|
||||||
|
r#"fn foo<B, B0, B1, B3>(bar: $0impl Bar) {}"#,
|
||||||
|
r#"fn foo<B, B0, B1, B3, $0B2: Bar>(bar: B2) {}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,38 +58,43 @@ const USELESS_METHODS: &[&str] = &[
|
||||||
"into_future",
|
"into_future",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub(crate) fn for_unique_generic_name(
|
pub(crate) fn for_generic_parameter(
|
||||||
name: &str,
|
ty: &ast::ImplTraitType,
|
||||||
existing_params: &ast::GenericParamList,
|
existing_params: &ast::GenericParamList,
|
||||||
) -> SmolStr {
|
) -> SmolStr {
|
||||||
let param_names = existing_params
|
|
||||||
.generic_params()
|
|
||||||
.map(|param| match param {
|
|
||||||
ast::GenericParam::TypeParam(t) => t.name().unwrap().to_string(),
|
|
||||||
p => p.to_string(),
|
|
||||||
})
|
|
||||||
.collect_vec();
|
|
||||||
let mut name = name.to_string();
|
|
||||||
let base_len = name.len();
|
|
||||||
// 4*len bytes for base, and 2 bytes for 2 digits
|
|
||||||
name.reserve(4 * base_len + 2);
|
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
while param_names.contains(&name) {
|
|
||||||
name.truncate(base_len);
|
|
||||||
name.push_str(&count.to_string());
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
name.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {
|
|
||||||
let c = ty
|
let c = ty
|
||||||
.type_bound_list()
|
.type_bound_list()
|
||||||
.and_then(|bounds| bounds.syntax().text().char_at(0.into()))
|
.and_then(|bounds| bounds.syntax().text().char_at(0.into()))
|
||||||
.unwrap_or('T');
|
.unwrap_or('T');
|
||||||
c.encode_utf8(&mut [0; 4]).into()
|
|
||||||
|
// let existing_params = existing_params.generic_params();
|
||||||
|
let conflict = existing_params
|
||||||
|
.generic_params()
|
||||||
|
.filter(|param| {
|
||||||
|
param.syntax().text_range().len() == 1.into()
|
||||||
|
&& param.syntax().text().char_at(0.into()).unwrap() == c
|
||||||
|
})
|
||||||
|
.count()
|
||||||
|
> 0;
|
||||||
|
|
||||||
|
let buffer = &mut [0; 4];
|
||||||
|
if conflict {
|
||||||
|
let mut name = String::from(c.encode_utf8(buffer));
|
||||||
|
name.reserve(6); // 4B for c, and 2B for 2 digits
|
||||||
|
let base_len = name.len();
|
||||||
|
let mut count = 0;
|
||||||
|
loop {
|
||||||
|
name.truncate(base_len);
|
||||||
|
name.push_str(&count.to_string());
|
||||||
|
if existing_params.generic_params().all(|param| param.to_string() != name) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
SmolStr::from(name)
|
||||||
|
} else {
|
||||||
|
c.encode_utf8(buffer).into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Suggest name of variable for given expression
|
/// Suggest name of variable for given expression
|
||||||
|
|
Loading…
Reference in a new issue