Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/utils/suggest_name.rs')
-rw-r--r--crates/ide-assists/src/utils/suggest_name.rs56
1 files changed, 53 insertions, 3 deletions
diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs
index 16704d598e..b4c6cbff2a 100644
--- a/crates/ide-assists/src/utils/suggest_name.rs
+++ b/crates/ide-assists/src/utils/suggest_name.rs
@@ -1,5 +1,7 @@
//! This module contains functions to suggest names for expressions, functions and other items
+use std::collections::HashSet;
+
use hir::Semantics;
use ide_db::RootDatabase;
use itertools::Itertools;
@@ -58,12 +60,59 @@ const USELESS_METHODS: &[&str] = &[
"into_future",
];
-pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {
+/// 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| match param {
+ ast::GenericParam::TypeParam(t) => t.name().unwrap().to_string(),
+ p => p.to_string(),
+ })
+ .collect::<HashSet<_>>();
+ let mut name = name.to_string();
+ let base_len = name.len();
+ 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 {
let c = ty
.type_bound_list()
.and_then(|bounds| bounds.syntax().text().char_at(0.into()))
.unwrap_or('T');
- c.encode_utf8(&mut [0; 4]).into()
+
+ for_unique_generic_name(c.encode_utf8(&mut [0; 4]), existing_params)
}
/// Suggest name of variable for given expression
@@ -275,7 +324,8 @@ fn from_field_name(expr: &ast::Expr) -> Option<String> {
#[cfg(test)]
mod tests {
- use ide_db::base_db::{fixture::WithFixture, FileRange};
+ use ide_db::base_db::FileRange;
+ use test_fixture::WithFixture;
use super::*;