Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/ide-assists/src/handlers/replace_method_eager_lazy.rs | 115 | ||||
| -rw-r--r-- | crates/test-utils/src/minicore.rs | 4 |
2 files changed, 112 insertions, 7 deletions
diff --git a/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs b/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs index 753f2ab5de..c85ec734c0 100644 --- a/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs +++ b/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs @@ -35,10 +35,7 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_ let (_, receiver_ty) = callable.receiver_param(ctx.sema.db)?; let n_params = callable.n_params() + 1; - let method_name_lazy = format!( - "{method_name}{}", - if method_name.text().ends_with("or") { "_else" } else { "_with" } - ); + let method_name_lazy = lazy_method_name(&method_name.text()); receiver_ty.iterate_method_candidates_with_traits( ctx.sema.db, @@ -70,6 +67,18 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_ ) } +fn lazy_method_name(name: &str) -> String { + if ends_is(name, "or") { + format!("{name}_else") + } else if ends_is(name, "and") { + format!("{name}_then") + } else if ends_is(name, "then_some") { + name.strip_suffix("_some").unwrap().to_owned() + } else { + format!("{name}_with") + } +} + fn into_closure(param: &Expr) -> Expr { (|| { if let ast::Expr::CallExpr(call) = param { @@ -117,9 +126,7 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<' } let method_name_text = method_name.text(); - let method_name_eager = method_name_text - .strip_suffix("_else") - .or_else(|| method_name_text.strip_suffix("_with"))?; + let method_name_eager = eager_method_name(&method_name_text)?; receiver_ty.iterate_method_candidates_with_traits( ctx.sema.db, @@ -156,6 +163,20 @@ fn into_call(param: &Expr) -> Expr { .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())).into()) } +fn eager_method_name(name: &str) -> Option<&str> { + if name == "then" { + return Some("then_some"); + } + + name.strip_suffix("_else") + .or_else(|| name.strip_suffix("_then")) + .or_else(|| name.strip_suffix("_with")) +} + +fn ends_is(name: &str, end: &str) -> bool { + name.strip_suffix(end).is_some_and(|s| s.is_empty() || s.ends_with('_')) +} + #[cfg(test)] mod tests { use crate::tests::check_assist; @@ -297,4 +318,84 @@ fn foo() { "#, ) } + + #[test] + fn replace_and_with_and_then() { + check_assist( + replace_with_lazy_method, + r#" +//- minicore: option, fn +fn foo() { + let foo = Some("foo"); + return foo.and$0(Some("bar")); +} +"#, + r#" +fn foo() { + let foo = Some("foo"); + return foo.and_then(|| Some("bar")); +} +"#, + ) + } + + #[test] + fn replace_and_then_with_and() { + check_assist( + replace_with_eager_method, + r#" +//- minicore: option, fn +fn foo() { + let foo = Some("foo"); + return foo.and_then$0(|| Some("bar")); +} +"#, + r#" +fn foo() { + let foo = Some("foo"); + return foo.and(Some("bar")); +} +"#, + ) + } + + #[test] + fn replace_then_some_with_then() { + check_assist( + replace_with_lazy_method, + r#" +//- minicore: option, fn, bool_impl +fn foo() { + let foo = true; + let x = foo.then_some$0(2); +} +"#, + r#" +fn foo() { + let foo = true; + let x = foo.then(|| 2); +} +"#, + ) + } + + #[test] + fn replace_then_with_then_some() { + check_assist( + replace_with_eager_method, + r#" +//- minicore: option, fn, bool_impl +fn foo() { + let foo = true; + let x = foo.then$0(|| 2); +} +"#, + r#" +fn foo() { + let foo = true; + let x = foo.then_some(2); +} +"#, + ) + } } diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 679fe420b0..0fe17e3075 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -1988,6 +1988,10 @@ pub mod num { // region:bool_impl #[lang = "bool"] impl bool { + pub fn then_some<T>(self, t: T) -> Option<T> { + if self { Some(t) } else { None } + } + pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> { if self { Some(f()) } else { None } } |