Unnamed repository; edit this file 'description' to name the repository.
feat: offer on is_some_and for replace_is_method_with_if_let_method
Example
---
```rust
fn main() {
let x = Some(1);
if x.is_som$0e_and(|it| it != 3) {}
}
```
**Before this PR**
Assist not applicable
**After this PR**
```rust
fn main() {
let x = Some(1);
if let Some(it) = x && it != 3 {}
}
```
| -rw-r--r-- | crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs index 5a2307739c..d22e951b5d 100644 --- a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs +++ b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs @@ -1,6 +1,6 @@ use either::Either; use ide_db::syntax_helpers::suggest_name; -use syntax::ast::{self, AstNode, syntax_factory::SyntaxFactory}; +use syntax::ast::{self, AstNode, HasArgList, syntax_factory::SyntaxFactory}; use crate::{AssistContext, AssistId, Assists, utils::cover_let_chain}; @@ -34,8 +34,9 @@ pub(crate) fn replace_is_method_with_if_let_method( _ => return None, }; - let name_ref = call_expr.name_ref()?; - match name_ref.text().as_str() { + let token = call_expr.name_ref()?.ident_token()?; + let method_kind = token.text().strip_suffix("_and").unwrap_or(token.text()); + match method_kind { "is_some" | "is_ok" => { let receiver = call_expr.receiver()?; @@ -47,8 +48,9 @@ pub(crate) fn replace_is_method_with_if_let_method( } else { name_generator.for_variable(&receiver, &ctx.sema) }; + let (pat, predicate) = method_predicate(&call_expr).unzip(); - let (assist_id, message, text) = if name_ref.text() == "is_some" { + let (assist_id, message, text) = if method_kind == "is_some" { ("replace_is_some_with_if_let_some", "Replace `is_some` with `let Some`", "Some") } else { ("replace_is_ok_with_if_let_ok", "Replace `is_ok` with `let Ok`", "Ok") @@ -62,19 +64,29 @@ pub(crate) fn replace_is_method_with_if_let_method( let make = SyntaxFactory::with_mappings(); let mut editor = edit.make_editor(call_expr.syntax()); - let var_pat = make.ident_pat(false, false, make.name(&var_name)); - let pat = make.tuple_struct_pat(make.ident_path(text), [var_pat.into()]); - let let_expr = make.expr_let(pat.into(), receiver); + let var_pat = pat.unwrap_or_else(|| { + make.ident_pat(false, false, make.name(&var_name)).into() + }); + let pat = make.tuple_struct_pat(make.ident_path(text), [var_pat]).into(); + let let_expr = make.expr_let(pat, receiver); if let Some(cap) = ctx.config.snippet_cap && let Some(ast::Pat::TupleStructPat(pat)) = let_expr.pat() && let Some(first_var) = pat.fields().next() + && predicate.is_none() { let placeholder = edit.make_placeholder_snippet(cap); editor.add_annotation(first_var.syntax(), placeholder); } - editor.replace(call_expr.syntax(), let_expr.syntax()); + let new_expr = if let Some(predicate) = predicate { + let op = ast::BinaryOp::LogicOp(ast::LogicOp::And); + make.expr_bin(let_expr.into(), op, predicate).into() + } else { + ast::Expr::from(let_expr) + }; + editor.replace(call_expr.syntax(), new_expr.syntax()); + editor.add_mappings(make.finish_with_mappings()); edit.add_file_edits(ctx.vfs_file_id(), editor); }, @@ -84,6 +96,17 @@ pub(crate) fn replace_is_method_with_if_let_method( } } +fn method_predicate(call_expr: &ast::MethodCallExpr) -> Option<(ast::Pat, ast::Expr)> { + let argument = call_expr.arg_list()?.args().next()?; + match argument { + ast::Expr::ClosureExpr(it) => { + let pat = it.param_list()?.params().next()?.pat()?; + Some((pat, it.body()?)) + } + _ => None, + } +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -195,6 +218,25 @@ fn main() { } #[test] + fn replace_is_some_and_with_if_let_chain_some_works() { + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + if x.is_som$0e_and(|it| it != 3) {} +} +"#, + r#" +fn main() { + let x = Some(1); + if let Some(it) = x && it != 3 {} +} +"#, + ); + } + + #[test] fn replace_is_some_with_if_let_some_in_let_chain() { check_assist( replace_is_method_with_if_let_method, |