Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #20526 from A4-Tacks/postfix-let-in-let-chain
Fix .let completion not work for let-chain
Shoyu Vanilla (Flint) 6 months ago
parent 87ccc2b · parent 38fed17 · commit b93180b
-rw-r--r--crates/ide-completion/src/completions/postfix.rs62
-rw-r--r--crates/ide-completion/src/context/analysis.rs33
2 files changed, 62 insertions, 33 deletions
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index d355fdbe07..51acdb7802 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -11,12 +11,12 @@ use ide_db::{
text_edit::TextEdit,
ty_filter::TryEnum,
};
-use itertools::Either;
use stdx::never;
use syntax::{
SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
- TextRange, TextSize,
+ T, TextRange, TextSize,
ast::{self, AstNode, AstToken},
+ match_ast,
};
use crate::{
@@ -113,12 +113,8 @@ pub(crate) fn complete_postfix(
if let Some(parent) = dot_receiver_including_refs.syntax().parent()
&& let Some(second_ancestor) = parent.parent()
{
- let sec_ancestor_kind = second_ancestor.kind();
- if let Some(expr) = <Either<ast::IfExpr, ast::WhileExpr>>::cast(second_ancestor) {
- is_in_cond = match expr {
- Either::Left(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent),
- Either::Right(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent),
- }
+ if let Some(parent_expr) = ast::Expr::cast(parent) {
+ is_in_cond = is_in_condition(&parent_expr);
}
match &try_enum {
Some(try_enum) if is_in_cond => match try_enum {
@@ -147,7 +143,7 @@ pub(crate) fn complete_postfix(
.add_to(acc, ctx.db);
}
},
- _ if matches!(sec_ancestor_kind, STMT_LIST | EXPR_STMT) => {
+ _ if matches!(second_ancestor.kind(), STMT_LIST | EXPR_STMT) => {
postfix_snippet("let", "let", &format!("let $0 = {receiver_text};"))
.add_to(acc, ctx.db);
postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};"))
@@ -454,6 +450,22 @@ fn add_custom_postfix_completions(
None
}
+pub(crate) fn is_in_condition(it: &ast::Expr) -> bool {
+ it.syntax()
+ .parent()
+ .and_then(|parent| {
+ Some(match_ast! { match parent {
+ ast::IfExpr(expr) => expr.condition()? == *it,
+ ast::WhileExpr(expr) => expr.condition()? == *it,
+ ast::MatchGuard(guard) => guard.condition()? == *it,
+ ast::BinExpr(bin_expr) => (bin_expr.op_token()?.kind() == T![&&])
+ .then(|| is_in_condition(&bin_expr.into()))?,
+ _ => return None,
+ } })
+ })
+ .unwrap_or(false)
+}
+
#[cfg(test)]
mod tests {
use expect_test::expect;
@@ -650,6 +662,38 @@ fn main() {
}
"#,
);
+ check_edit(
+ "let",
+ r#"
+//- minicore: option
+fn main() {
+ let bar = Some(true);
+ if true && bar.$0
+}
+"#,
+ r#"
+fn main() {
+ let bar = Some(true);
+ if true && let Some($0) = bar
+}
+"#,
+ );
+ check_edit(
+ "let",
+ r#"
+//- minicore: option
+fn main() {
+ let bar = Some(true);
+ if true && true && bar.$0
+}
+"#,
+ r#"
+fn main() {
+ let bar = Some(true);
+ if true && true && let Some($0) = bar
+}
+"#,
+ );
}
#[test]
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 0b8ba808e5..440ac9ad07 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -19,12 +19,15 @@ use syntax::{
match_ast,
};
-use crate::context::{
- AttrCtx, BreakableKind, COMPLETION_MARKER, CompletionAnalysis, DotAccess, DotAccessExprCtx,
- DotAccessKind, ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind,
- NameRefContext, NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathExprCtx, PathKind,
- PatternContext, PatternRefutability, Qualified, QualifierCtx, TypeAscriptionTarget,
- TypeLocation,
+use crate::{
+ completions::postfix::is_in_condition,
+ context::{
+ AttrCtx, BreakableKind, COMPLETION_MARKER, CompletionAnalysis, DotAccess, DotAccessExprCtx,
+ DotAccessKind, ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind,
+ NameRefContext, NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathExprCtx,
+ PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx,
+ TypeAscriptionTarget, TypeLocation,
+ },
};
#[derive(Debug)]
@@ -1223,24 +1226,6 @@ fn classify_name_ref<'db>(
Some(res)
};
- fn is_in_condition(it: &ast::Expr) -> bool {
- (|| {
- let parent = it.syntax().parent()?;
- if let Some(expr) = ast::WhileExpr::cast(parent.clone()) {
- Some(expr.condition()? == *it)
- } else if let Some(expr) = ast::IfExpr::cast(parent.clone()) {
- Some(expr.condition()? == *it)
- } else if let Some(expr) = ast::BinExpr::cast(parent)
- && expr.op_token()?.kind() == T![&&]
- {
- Some(is_in_condition(&expr.into()))
- } else {
- None
- }
- })()
- .unwrap_or(false)
- }
-
let make_path_kind_expr = |expr: ast::Expr| {
let it = expr.syntax();
let in_block_expr = is_in_block(it);