Unnamed repository; edit this file 'description' to name the repository.
Fix not applicable on let-chain for replace_is_method_with_if_let_method
Example --- ```rust fn main() { let x = Some(1); let cond = true; if cond && x.is_som$0e() {} } ``` **Before this PR** Assist not applicable **After this PR** ```rust fn main() { let x = Some(1); let cond = true; if cond && let Some(${0:x1}) = x {} } ```
A4-Tacks 6 months ago
parent 808c931 · commit d2f97dd
-rw-r--r--crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs63
-rw-r--r--crates/ide-assists/src/utils.rs22
2 files changed, 81 insertions, 4 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 f507cae1bb..c57fd4d439 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,7 +1,7 @@
use ide_db::syntax_helpers::suggest_name;
use syntax::ast::{self, AstNode, syntax_factory::SyntaxFactory};
-use crate::{AssistContext, AssistId, Assists};
+use crate::{AssistContext, AssistId, Assists, utils::cover_let_chain};
// Assist: replace_is_some_with_if_let_some
//
@@ -27,13 +27,11 @@ pub(crate) fn replace_is_method_with_if_let_method(
let if_expr = ctx.find_node_at_offset::<ast::IfExpr>()?;
let cond = if_expr.condition()?;
+ let cond = cover_let_chain(cond, ctx.selection_trimmed())?;
let call_expr = match cond {
ast::Expr::MethodCallExpr(call) => call,
_ => return None,
};
- if ctx.offset() > if_expr.then_branch()?.stmt_list()?.l_curly_token()?.text_range().end() {
- return None;
- }
let name_ref = call_expr.name_ref()?;
match name_ref.text().as_str() {
@@ -196,6 +194,63 @@ fn main() {
}
#[test]
+ fn replace_is_some_with_if_let_some_in_let_chain() {
+ check_assist(
+ replace_is_method_with_if_let_method,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if cond && x.is_som$0e() {}
+}
+"#,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if cond && let Some(${0:x1}) = x {}
+}
+"#,
+ );
+
+ check_assist(
+ replace_is_method_with_if_let_method,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if x.is_som$0e() && cond {}
+}
+"#,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if let Some(${0:x1}) = x && cond {}
+}
+"#,
+ );
+
+ check_assist(
+ replace_is_method_with_if_let_method,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if cond && x.is_som$0e() && cond {}
+}
+"#,
+ r#"
+fn main() {
+ let x = Some(1);
+ let cond = true;
+ if cond && let Some(${0:x1}) = x && cond {}
+}
+"#,
+ );
+ }
+
+ #[test]
fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() {
check_assist_not_applicable(
replace_is_method_with_if_let_method,
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 5a3c5a39da..e43516f6b9 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -1133,6 +1133,28 @@ pub(crate) fn tt_from_syntax(node: SyntaxNode) -> Vec<NodeOrToken<ast::TokenTree
tt_stack.pop().expect("parent token tree was closed before it was completed").1
}
+pub(crate) fn cover_let_chain(mut expr: ast::Expr, range: TextRange) -> Option<ast::Expr> {
+ if !expr.syntax().text_range().contains_range(range) {
+ return None;
+ }
+ loop {
+ let (chain_expr, rest) = if let ast::Expr::BinExpr(bin_expr) = &expr
+ && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
+ {
+ (bin_expr.rhs(), bin_expr.lhs())
+ } else {
+ (Some(expr), None)
+ };
+
+ if let Some(chain_expr) = chain_expr
+ && chain_expr.syntax().text_range().contains_range(range)
+ {
+ break Some(chain_expr);
+ }
+ expr = rest?;
+ }
+}
+
pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bool {
let mut is_const = true;
preorder_expr(expr, &mut |ev| {