Skip to content

Commit 17557ff

Browse files
Add method for_lifetime for NameGenerator
1 parent cec000f commit 17557ff

File tree

1 file changed

+71
-1
lines changed

1 file changed

+71
-1
lines changed

crates/ide-db/src/syntax_helpers/suggest_name.rs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use stdx::to_lower_snake_case;
99
use syntax::{
1010
AstNode, Edition, SmolStr, SmolStrBuilder, ToSmolStr,
1111
ast::{self, HasName},
12-
match_ast,
12+
format_smolstr, match_ast,
1313
};
1414

1515
use crate::RootDatabase;
@@ -232,6 +232,40 @@ impl NameGenerator {
232232
self.suggest_name("var_name")
233233
}
234234

235+
/// Suggest a unique lifetime name following Rust conventions.
236+
///
237+
/// Generates lifetime names in alphabetical order: `'a`, `'b`, `'c`, ..., `'z`.
238+
/// This follows Rust's idiomatic lifetime naming conventions.
239+
///
240+
/// # Examples
241+
///
242+
/// ```
243+
/// # use ide_db::syntax_helpers::suggest_name::NameGenerator;
244+
/// let mut gen = NameGenerator::default();
245+
/// assert_eq!(gen.for_lifetime(), "'a");
246+
/// assert_eq!(gen.for_lifetime(), "'b");
247+
/// assert_eq!(gen.for_lifetime(), "'c");
248+
/// ```
249+
///
250+
/// When initialized with existing lifetimes:
251+
///
252+
/// ```
253+
/// # use ide_db::syntax_helpers::suggest_name::NameGenerator;
254+
/// let mut gen = NameGenerator::new_with_names(["'a", "'c"].iter().copied());
255+
/// assert_eq!(gen.for_lifetime(), "'b");
256+
/// assert_eq!(gen.for_lifetime(), "'d");
257+
/// ```
258+
pub fn for_lifetime(&mut self) -> SmolStr {
259+
for c in 'a'..='z' {
260+
let candidate = format_smolstr!("'{c}");
261+
if !self.pool.contains_key(&candidate) {
262+
self.pool.insert(candidate.clone(), 0);
263+
return candidate;
264+
}
265+
}
266+
self.suggest_name("'a")
267+
}
268+
235269
/// Insert a name into the pool
236270
fn insert(&mut self, name: &str) {
237271
let (prefix, suffix) = Self::split_numeric_suffix(name);
@@ -1142,4 +1176,40 @@ fn main() {
11421176

11431177
assert_eq!(generator.suggest_name("c"), "c5");
11441178
}
1179+
1180+
#[test]
1181+
fn for_lifetime_generates_alphabetical_names() {
1182+
let mut generator = NameGenerator::default();
1183+
assert_eq!(generator.for_lifetime(), "'a");
1184+
assert_eq!(generator.for_lifetime(), "'b");
1185+
assert_eq!(generator.for_lifetime(), "'c");
1186+
}
1187+
1188+
#[test]
1189+
fn for_lifetime_avoids_existing_names() {
1190+
let mut generator =
1191+
NameGenerator::new_with_names(["'a", "'b", "'d", "'e", "'f"].into_iter());
1192+
assert_eq!(generator.for_lifetime(), "'c");
1193+
assert_eq!(generator.for_lifetime(), "'g");
1194+
}
1195+
1196+
#[test]
1197+
fn for_lifetime_exhaustive() {
1198+
let mut generator = NameGenerator::default();
1199+
let mut lifetimes = Vec::new();
1200+
for _ in 0..10 {
1201+
lifetimes.push(generator.for_lifetime());
1202+
}
1203+
assert_eq!(lifetimes[0], "'a");
1204+
assert_eq!(lifetimes[1], "'b");
1205+
assert_eq!(lifetimes[9], "'j");
1206+
}
1207+
1208+
#[test]
1209+
fn for_lifetime_fallback_when_exhausted() {
1210+
let all_lifetimes: Vec<_> = ('a'..='z').map(|c| format!("'{c}")).collect();
1211+
let mut generator = NameGenerator::new_with_names(all_lifetimes.iter().map(|s| s.as_str()));
1212+
let fallback = generator.for_lifetime();
1213+
assert_eq!(fallback, "'a1");
1214+
}
11451215
}

0 commit comments

Comments
 (0)