diff --git a/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs b/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs new file mode 100644 index 0000000000000..70892fe27025d --- /dev/null +++ b/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs @@ -0,0 +1,90 @@ +use syntax::ast::{self, AstNode}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: replace_is_some_with_if_let_some +// +// Replace `if x.is_some()` with `if let Some(_tmp) = x`. +// +// ``` +// fn main() { +// let x = Some(1); +// if x.is_som$0e() {} +// } +// ``` +// -> +// ``` +// fn main() { +// let x = Some(1); +// if let Some(_tmp) = x {} +// } +// ``` +pub(crate) fn replace_is_some_with_if_let_some( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + let if_expr = ctx.find_node_at_offset::()?; + + let cond = if_expr.condition()?; + let call_expr = match cond { + ast::Expr::MethodCallExpr(call) => call, + _ => return None, + }; + + let name_ref = call_expr.name_ref()?; + if name_ref.text() != "is_some" { + return None; + } + + let receiver = call_expr.receiver()?; + let target = call_expr.syntax().text_range(); + + acc.add( + AssistId("replace_is_some_with_if_let_some", AssistKind::RefactorRewrite), + "Replace `is_some` with `if let Some`", + target, + |edit| { + let replacement = format!("let Some(_tmp) = {}", receiver); + edit.replace(target, replacement); + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::replace_is_some_with_if_let_some; + + #[test] + fn replace_is_some_with_if_let_some_works() { + check_assist( + replace_is_some_with_if_let_some, + r#" +fn main() { + let x = Some(1); + if x.is_som$0e() {} +} +"#, + r#" +fn main() { + let x = Some(1); + if let Some(_tmp) = x {} +} +"#, + ); + } + + #[test] + fn replace_is_some_with_if_let_some_not_applicable() { + check_assist_not_applicable( + replace_is_some_with_if_let_some, + r#" +fn main() { + let x = Some(1); + if x.is_non$0e() {} +} +"#, + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 7b1961ae5493c..d6accbb097eec 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -213,6 +213,7 @@ mod handlers { mod unwrap_block; mod unwrap_result_return_type; mod unqualify_method_call; + mod replace_is_some_with_if_let_some; mod wrap_return_type_in_result; mod into_to_qualified_from; @@ -332,6 +333,7 @@ mod handlers { unwrap_result_return_type::unwrap_result_return_type, unwrap_tuple::unwrap_tuple, unqualify_method_call::unqualify_method_call, + replace_is_some_with_if_let_some::replace_is_some_with_if_let_some, wrap_return_type_in_result::wrap_return_type_in_result, // These are manually sorted for better priorities. By default, // priority is determined by the size of the target range (smaller diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 18f7591cf0826..d2b801336a55c 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -2558,6 +2558,25 @@ fn handle(action: Action) { ) } +#[test] +fn doctest_replace_is_some_with_if_let_some() { + check_doc_test( + "replace_is_some_with_if_let_some", + r#####" +fn main() { + let x = Some(1); + if x.is_som$0e() {} +} +"#####, + r#####" +fn main() { + let x = Some(1); + if let Some(_tmp) = x {} +} +"#####, + ) +} + #[test] fn doctest_replace_let_with_if_let() { check_doc_test(