refactor: extracted the fn handling conflicts in generics and add docs
* Extracted the function `for_unique_generic_name` that handling generics with identical names for reusability. * Renamed `for_generic_params` to `for_impl_trait_as_generic` for clarity * Added documentations for `for_impl_trait_as_generic` and `for_unique_generic_name`
This commit is contained in:
parent
e8dc8ccc59
commit
186553dab8
@ -33,7 +33,7 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_>
|
|||||||
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 fn_generic_param_list = fn_.get_or_create_generic_param_list();
|
||||||
let type_param_name =
|
let type_param_name =
|
||||||
suggest_name::for_generic_parameter(&impl_trait_type, &fn_generic_param_list);
|
suggest_name::for_impl_trait_as_generic(&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();
|
||||||
|
@ -58,7 +58,48 @@
|
|||||||
"into_future",
|
"into_future",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub(crate) fn for_generic_parameter(
|
/// Suggest a unique name for generic parameter.
|
||||||
|
///
|
||||||
|
/// `existing_params` is used to check if the name conflicts with existing
|
||||||
|
/// generic parameters.
|
||||||
|
///
|
||||||
|
/// The function checks if the name conflicts with existing generic parameters.
|
||||||
|
/// If so, it will try to resolve the conflict by adding a number suffix, e.g.
|
||||||
|
/// `T`, `T0`, `T1`, ...
|
||||||
|
pub(crate) fn for_unique_generic_name(
|
||||||
|
name: &str,
|
||||||
|
existing_params: &ast::GenericParamList,
|
||||||
|
) -> SmolStr {
|
||||||
|
let param_names = existing_params.generic_params().map(|param| param.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()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Suggest name of impl trait type
|
||||||
|
///
|
||||||
|
/// `existing_params` is used to check if the name conflicts with existing
|
||||||
|
/// generic parameters.
|
||||||
|
///
|
||||||
|
/// # Current implementation
|
||||||
|
///
|
||||||
|
/// In current implementation, the function tries to get the name from the first
|
||||||
|
/// character of the name for the first type bound.
|
||||||
|
///
|
||||||
|
/// If the name conflicts with existing generic parameters, it will try to
|
||||||
|
/// resolve the conflict with `for_unique_generic_name`.
|
||||||
|
pub(crate) fn for_impl_trait_as_generic(
|
||||||
ty: &ast::ImplTraitType,
|
ty: &ast::ImplTraitType,
|
||||||
existing_params: &ast::GenericParamList,
|
existing_params: &ast::GenericParamList,
|
||||||
) -> SmolStr {
|
) -> SmolStr {
|
||||||
@ -67,34 +108,7 @@ pub(crate) fn for_generic_parameter(
|
|||||||
.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');
|
||||||
|
|
||||||
// let existing_params = existing_params.generic_params();
|
for_unique_generic_name(c.encode_utf8(&mut [0; 4]), existing_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 New Issue
Block a user