Skip to content

Commit 93baf96

Browse files
committed
Fix not applicable on and for replace_method_eager_lazy
Supports: - and <-> and_then - then_some <-> then Example --- ```rust fn foo() { let foo = Some("foo"); return foo.and$0(Some("bar")); } ``` **Before this PR** Assist not applicable **After this PR** ```rust fn foo() { let foo = Some("foo"); return foo.and_then(|| Some("bar")); } ```
1 parent c46279d commit 93baf96

File tree

2 files changed

+112
-7
lines changed

2 files changed

+112
-7
lines changed

crates/ide-assists/src/handlers/replace_method_eager_lazy.rs

Lines changed: 108 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,7 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_
3535
let (_, receiver_ty) = callable.receiver_param(ctx.sema.db)?;
3636
let n_params = callable.n_params() + 1;
3737

38-
let method_name_lazy = format!(
39-
"{method_name}{}",
40-
if method_name.text().ends_with("or") { "_else" } else { "_with" }
41-
);
38+
let method_name_lazy = lazy_method_name(&method_name.text());
4239

4340
receiver_ty.iterate_method_candidates_with_traits(
4441
ctx.sema.db,
@@ -71,6 +68,18 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_
7168
)
7269
}
7370

71+
fn lazy_method_name(name: &str) -> String {
72+
if ends_is(name, "or") {
73+
format!("{name}_else")
74+
} else if ends_is(name, "and") {
75+
format!("{name}_then")
76+
} else if ends_is(name, "then_some") {
77+
name.strip_suffix("_some").unwrap().to_owned()
78+
} else {
79+
format!("{name}_with")
80+
}
81+
}
82+
7483
fn into_closure(param: &Expr) -> Expr {
7584
(|| {
7685
if let ast::Expr::CallExpr(call) = param {
@@ -118,9 +127,7 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<'
118127
}
119128

120129
let method_name_text = method_name.text();
121-
let method_name_eager = method_name_text
122-
.strip_suffix("_else")
123-
.or_else(|| method_name_text.strip_suffix("_with"))?;
130+
let method_name_eager = eager_method_name(&method_name_text)?;
124131

125132
receiver_ty.iterate_method_candidates_with_traits(
126133
ctx.sema.db,
@@ -158,6 +165,20 @@ fn into_call(param: &Expr) -> Expr {
158165
.unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())).into())
159166
}
160167

168+
fn eager_method_name(name: &str) -> Option<&str> {
169+
if name == "then" {
170+
return Some("then_some");
171+
}
172+
173+
name.strip_suffix("_else")
174+
.or_else(|| name.strip_suffix("_then"))
175+
.or_else(|| name.strip_suffix("_with"))
176+
}
177+
178+
fn ends_is(name: &str, end: &str) -> bool {
179+
name.strip_suffix(end).is_some_and(|s| s.is_empty() || s.ends_with('_'))
180+
}
181+
161182
#[cfg(test)]
162183
mod tests {
163184
use crate::tests::check_assist;
@@ -296,6 +317,86 @@ fn foo() {
296317
let foo = Some("foo");
297318
return foo.map_or(42, |v| v.len());
298319
}
320+
"#,
321+
)
322+
}
323+
324+
#[test]
325+
fn replace_and_with_and_then() {
326+
check_assist(
327+
replace_with_lazy_method,
328+
r#"
329+
//- minicore: option, fn
330+
fn foo() {
331+
let foo = Some("foo");
332+
return foo.and$0(Some("bar"));
333+
}
334+
"#,
335+
r#"
336+
fn foo() {
337+
let foo = Some("foo");
338+
return foo.and_then(|| Some("bar"));
339+
}
340+
"#,
341+
)
342+
}
343+
344+
#[test]
345+
fn replace_and_then_with_and() {
346+
check_assist(
347+
replace_with_eager_method,
348+
r#"
349+
//- minicore: option, fn
350+
fn foo() {
351+
let foo = Some("foo");
352+
return foo.and_then$0(|| Some("bar"));
353+
}
354+
"#,
355+
r#"
356+
fn foo() {
357+
let foo = Some("foo");
358+
return foo.and(Some("bar"));
359+
}
360+
"#,
361+
)
362+
}
363+
364+
#[test]
365+
fn replace_then_some_with_then() {
366+
check_assist(
367+
replace_with_lazy_method,
368+
r#"
369+
//- minicore: option, fn, bool_impl
370+
fn foo() {
371+
let foo = true;
372+
let x = foo.then_some$0(2);
373+
}
374+
"#,
375+
r#"
376+
fn foo() {
377+
let foo = true;
378+
let x = foo.then(|| 2);
379+
}
380+
"#,
381+
)
382+
}
383+
384+
#[test]
385+
fn replace_then_with_then_some() {
386+
check_assist(
387+
replace_with_eager_method,
388+
r#"
389+
//- minicore: option, fn, bool_impl
390+
fn foo() {
391+
let foo = true;
392+
let x = foo.then$0(|| 2);
393+
}
394+
"#,
395+
r#"
396+
fn foo() {
397+
let foo = true;
398+
let x = foo.then_some(2);
399+
}
299400
"#,
300401
)
301402
}

crates/test-utils/src/minicore.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,6 +1954,10 @@ pub mod num {
19541954
// region:bool_impl
19551955
#[lang = "bool"]
19561956
impl bool {
1957+
pub fn then_some<T>(self, t: T) -> Option<T> {
1958+
if self { Some(t) } else { None }
1959+
}
1960+
19571961
pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
19581962
if self { Some(f()) } else { None }
19591963
}

0 commit comments

Comments
 (0)