Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-assists/src/handlers/introduce_named_generic.rs2
-rw-r--r--crates/ide-assists/src/utils/suggest_name.rs72
2 files changed, 44 insertions, 30 deletions
diff --git a/crates/ide-assists/src/handlers/introduce_named_generic.rs b/crates/ide-assists/src/handlers/introduce_named_generic.rs
index abbdc5aee9..b1daa7802e 100644
--- a/crates/ide-assists/src/handlers/introduce_named_generic.rs
+++ b/crates/ide-assists/src/handlers/introduce_named_generic.rs
@@ -33,7 +33,7 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_>
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, &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))
.clone_for_update();
diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs
index ae3fd30b65..8a698e4068 100644
--- a/crates/ide-assists/src/utils/suggest_name.rs
+++ b/crates/ide-assists/src/utils/suggest_name.rs
@@ -58,7 +58,48 @@ const USELESS_METHODS: &[&str] = &[
"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,
existing_params: &ast::GenericParamList,
) -> SmolStr {
@@ -67,34 +108,7 @@ pub(crate) fn for_generic_parameter(
.and_then(|bounds| bounds.syntax().text().char_at(0.into()))
.unwrap_or('T');
- // 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()
- }
+ for_unique_generic_name(c.encode_utf8(&mut [0; 4]), existing_params)
}
/// Suggest name of variable for given expression