Skip to content

Commit 3d25a36

Browse files
committed
Fix .let completion not work for let-chain
Example --- ```rust fn main() { let bar = Some(true); if true && bar.$0 } ``` **Before this PR**: Cannot complete `.let` **After this PR**: ```rust fn main() { let bar = Some(true); if true && let Some($0) = bar } ```
1 parent 7de38d3 commit 3d25a36

File tree

2 files changed

+62
-33
lines changed

2 files changed

+62
-33
lines changed

src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ use ide_db::{
1111
text_edit::TextEdit,
1212
ty_filter::TryEnum,
1313
};
14-
use itertools::Either;
1514
use stdx::never;
1615
use syntax::{
1716
SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
18-
TextRange, TextSize,
17+
T, TextRange, TextSize,
1918
ast::{self, AstNode, AstToken},
19+
match_ast,
2020
};
2121

2222
use crate::{
@@ -113,12 +113,8 @@ pub(crate) fn complete_postfix(
113113
if let Some(parent) = dot_receiver_including_refs.syntax().parent()
114114
&& let Some(second_ancestor) = parent.parent()
115115
{
116-
let sec_ancestor_kind = second_ancestor.kind();
117-
if let Some(expr) = <Either<ast::IfExpr, ast::WhileExpr>>::cast(second_ancestor) {
118-
is_in_cond = match expr {
119-
Either::Left(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent),
120-
Either::Right(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent),
121-
}
116+
if let Some(parent_expr) = ast::Expr::cast(parent) {
117+
is_in_cond = is_in_condition(&parent_expr);
122118
}
123119
match &try_enum {
124120
Some(try_enum) if is_in_cond => match try_enum {
@@ -147,7 +143,7 @@ pub(crate) fn complete_postfix(
147143
.add_to(acc, ctx.db);
148144
}
149145
},
150-
_ if matches!(sec_ancestor_kind, STMT_LIST | EXPR_STMT) => {
146+
_ if matches!(second_ancestor.kind(), STMT_LIST | EXPR_STMT) => {
151147
postfix_snippet("let", "let", &format!("let $0 = {receiver_text};"))
152148
.add_to(acc, ctx.db);
153149
postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};"))
@@ -454,6 +450,22 @@ fn add_custom_postfix_completions(
454450
None
455451
}
456452

453+
pub(crate) fn is_in_condition(it: &ast::Expr) -> bool {
454+
it.syntax()
455+
.parent()
456+
.and_then(|parent| {
457+
Some(match_ast! { match parent {
458+
ast::IfExpr(expr) => expr.condition()? == *it,
459+
ast::WhileExpr(expr) => expr.condition()? == *it,
460+
ast::MatchGuard(guard) => guard.condition()? == *it,
461+
ast::BinExpr(bin_expr) => (bin_expr.op_token()?.kind() == T![&&])
462+
.then(|| is_in_condition(&bin_expr.into()))?,
463+
_ => return None,
464+
} })
465+
})
466+
.unwrap_or(false)
467+
}
468+
457469
#[cfg(test)]
458470
mod tests {
459471
use expect_test::expect;
@@ -648,6 +660,38 @@ fn main() {
648660
let bar = Some(true);
649661
if let Some($0) = bar
650662
}
663+
"#,
664+
);
665+
check_edit(
666+
"let",
667+
r#"
668+
//- minicore: option
669+
fn main() {
670+
let bar = Some(true);
671+
if true && bar.$0
672+
}
673+
"#,
674+
r#"
675+
fn main() {
676+
let bar = Some(true);
677+
if true && let Some($0) = bar
678+
}
679+
"#,
680+
);
681+
check_edit(
682+
"let",
683+
r#"
684+
//- minicore: option
685+
fn main() {
686+
let bar = Some(true);
687+
if true && true && bar.$0
688+
}
689+
"#,
690+
r#"
691+
fn main() {
692+
let bar = Some(true);
693+
if true && true && let Some($0) = bar
694+
}
651695
"#,
652696
);
653697
}

src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@ use syntax::{
2020
match_ast,
2121
};
2222

23-
use crate::context::{
24-
AttrCtx, BreakableKind, COMPLETION_MARKER, CompletionAnalysis, DotAccess, DotAccessExprCtx,
25-
DotAccessKind, ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind,
26-
NameRefContext, NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathExprCtx, PathKind,
27-
PatternContext, PatternRefutability, Qualified, QualifierCtx, TypeAscriptionTarget,
28-
TypeLocation,
23+
use crate::{
24+
completions::postfix::is_in_condition,
25+
context::{
26+
AttrCtx, BreakableKind, COMPLETION_MARKER, CompletionAnalysis, DotAccess, DotAccessExprCtx,
27+
DotAccessKind, ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind,
28+
NameRefContext, NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathExprCtx,
29+
PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx,
30+
TypeAscriptionTarget, TypeLocation,
31+
},
2932
};
3033

3134
#[derive(Debug)]
@@ -1216,24 +1219,6 @@ fn classify_name_ref<'db>(
12161219
Some(res)
12171220
};
12181221

1219-
fn is_in_condition(it: &ast::Expr) -> bool {
1220-
(|| {
1221-
let parent = it.syntax().parent()?;
1222-
if let Some(expr) = ast::WhileExpr::cast(parent.clone()) {
1223-
Some(expr.condition()? == *it)
1224-
} else if let Some(expr) = ast::IfExpr::cast(parent.clone()) {
1225-
Some(expr.condition()? == *it)
1226-
} else if let Some(expr) = ast::BinExpr::cast(parent)
1227-
&& expr.op_token()?.kind() == T![&&]
1228-
{
1229-
Some(is_in_condition(&expr.into()))
1230-
} else {
1231-
None
1232-
}
1233-
})()
1234-
.unwrap_or(false)
1235-
}
1236-
12371222
let make_path_kind_expr = |expr: ast::Expr| {
12381223
let it = expr.syntax();
12391224
let in_block_expr = is_in_block(it);

0 commit comments

Comments
 (0)