Skip to content

Commit f62cb38

Browse files
authored
Merge pull request rust-lang#20913 from A4-Tacks/if-let-chain-for-is-method-with-if-let
Fix not applicable on let-chain for replace_is_method_with_if_let_method
2 parents 165065a + 95e2b84 commit f62cb38

File tree

2 files changed

+81
-4
lines changed

2 files changed

+81
-4
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use ide_db::syntax_helpers::suggest_name;
22
use syntax::ast::{self, AstNode, syntax_factory::SyntaxFactory};
33

4-
use crate::{AssistContext, AssistId, Assists};
4+
use crate::{AssistContext, AssistId, Assists, utils::cover_let_chain};
55

66
// Assist: replace_is_some_with_if_let_some
77
//
@@ -27,13 +27,11 @@ pub(crate) fn replace_is_method_with_if_let_method(
2727
let if_expr = ctx.find_node_at_offset::<ast::IfExpr>()?;
2828

2929
let cond = if_expr.condition()?;
30+
let cond = cover_let_chain(cond, ctx.selection_trimmed())?;
3031
let call_expr = match cond {
3132
ast::Expr::MethodCallExpr(call) => call,
3233
_ => return None,
3334
};
34-
if ctx.offset() > if_expr.then_branch()?.stmt_list()?.l_curly_token()?.text_range().end() {
35-
return None;
36-
}
3735

3836
let name_ref = call_expr.name_ref()?;
3937
match name_ref.text().as_str() {
@@ -195,6 +193,63 @@ fn main() {
195193
);
196194
}
197195

196+
#[test]
197+
fn replace_is_some_with_if_let_some_in_let_chain() {
198+
check_assist(
199+
replace_is_method_with_if_let_method,
200+
r#"
201+
fn main() {
202+
let x = Some(1);
203+
let cond = true;
204+
if cond && x.is_som$0e() {}
205+
}
206+
"#,
207+
r#"
208+
fn main() {
209+
let x = Some(1);
210+
let cond = true;
211+
if cond && let Some(${0:x1}) = x {}
212+
}
213+
"#,
214+
);
215+
216+
check_assist(
217+
replace_is_method_with_if_let_method,
218+
r#"
219+
fn main() {
220+
let x = Some(1);
221+
let cond = true;
222+
if x.is_som$0e() && cond {}
223+
}
224+
"#,
225+
r#"
226+
fn main() {
227+
let x = Some(1);
228+
let cond = true;
229+
if let Some(${0:x1}) = x && cond {}
230+
}
231+
"#,
232+
);
233+
234+
check_assist(
235+
replace_is_method_with_if_let_method,
236+
r#"
237+
fn main() {
238+
let x = Some(1);
239+
let cond = true;
240+
if cond && x.is_som$0e() && cond {}
241+
}
242+
"#,
243+
r#"
244+
fn main() {
245+
let x = Some(1);
246+
let cond = true;
247+
if cond && let Some(${0:x1}) = x && cond {}
248+
}
249+
"#,
250+
);
251+
}
252+
198253
#[test]
199254
fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() {
200255
check_assist_not_applicable(

src/tools/rust-analyzer/crates/ide-assists/src/utils.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,28 @@ pub(crate) fn tt_from_syntax(node: SyntaxNode) -> Vec<NodeOrToken<ast::TokenTree
11331133
tt_stack.pop().expect("parent token tree was closed before it was completed").1
11341134
}
11351135

1136+
pub(crate) fn cover_let_chain(mut expr: ast::Expr, range: TextRange) -> Option<ast::Expr> {
1137+
if !expr.syntax().text_range().contains_range(range) {
1138+
return None;
1139+
}
1140+
loop {
1141+
let (chain_expr, rest) = if let ast::Expr::BinExpr(bin_expr) = &expr
1142+
&& bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
1143+
{
1144+
(bin_expr.rhs(), bin_expr.lhs())
1145+
} else {
1146+
(Some(expr), None)
1147+
};
1148+
1149+
if let Some(chain_expr) = chain_expr
1150+
&& chain_expr.syntax().text_range().contains_range(range)
1151+
{
1152+
break Some(chain_expr);
1153+
}
1154+
expr = rest?;
1155+
}
1156+
}
1157+
11361158
pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bool {
11371159
let mut is_const = true;
11381160
preorder_expr(expr, &mut |ev| {

0 commit comments

Comments
 (0)