Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/completions/postfix.rs')
-rw-r--r--crates/ide-completion/src/completions/postfix.rs208
1 files changed, 189 insertions, 19 deletions
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index cffc44f8af..ea53aef40c 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -52,6 +52,7 @@ pub(crate) fn complete_postfix(
_ => return,
};
let expr_ctx = &dot_access.ctx;
+ let receiver_accessor = receiver_accessor(dot_receiver);
let receiver_text =
get_receiver_text(&ctx.sema, dot_receiver, receiver_is_ambiguous_float_literal);
@@ -90,9 +91,8 @@ pub(crate) fn complete_postfix(
// The rest of the postfix completions create an expression that moves an argument,
// so it's better to consider references now to avoid breaking the compilation
- let (dot_receiver_including_refs, prefix) = include_references(dot_receiver);
- let mut receiver_text =
- get_receiver_text(&ctx.sema, dot_receiver, receiver_is_ambiguous_float_literal);
+ let (dot_receiver_including_refs, prefix) = include_references(&receiver_accessor);
+ let mut receiver_text = receiver_text;
receiver_text.insert_str(0, &prefix);
let postfix_snippet =
match build_postfix_snippet_builder(ctx, cap, &dot_receiver_including_refs) {
@@ -111,14 +111,9 @@ pub(crate) fn complete_postfix(
postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})"))
.add_to(acc, ctx.db);
- let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references());
- let mut is_in_cond = false;
- if let Some(parent) = dot_receiver_including_refs.syntax().parent()
- && let Some(second_ancestor) = parent.parent()
- {
- if let Some(parent_expr) = ast::Expr::cast(parent) {
- is_in_cond = is_in_condition(&parent_expr);
- }
+ let try_enum = TryEnum::from_ty(&ctx.sema, receiver_ty);
+ let is_in_cond = is_in_condition(&dot_receiver_including_refs);
+ if let Some(parent) = dot_receiver_including_refs.syntax().parent() {
let placeholder = suggest_receiver_name(dot_receiver, "0", &ctx.sema);
match &try_enum {
Some(try_enum) if is_in_cond => match try_enum {
@@ -155,12 +150,26 @@ pub(crate) fn complete_postfix(
postfix_snippet("let", "let", &format!("let $1 = {receiver_text}"))
.add_to(acc, ctx.db);
}
- _ if matches!(second_ancestor.kind(), STMT_LIST | EXPR_STMT) => {
+ _ if matches!(parent.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};"))
.add_to(acc, ctx.db);
}
+ _ if ast::MatchArm::can_cast(parent.kind()) => {
+ postfix_snippet(
+ "let",
+ "let",
+ &format!("{{\n let $1 = {receiver_text};\n $0\n}}"),
+ )
+ .add_to(acc, ctx.db);
+ postfix_snippet(
+ "letm",
+ "let mut",
+ &format!("{{\n let mut $1 = {receiver_text};\n $0\n}}"),
+ )
+ .add_to(acc, ctx.db);
+ }
_ => (),
}
}
@@ -292,7 +301,7 @@ pub(crate) fn complete_postfix(
postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db);
}
- if let ast::Expr::Literal(literal) = dot_receiver_including_refs.clone()
+ if let ast::Expr::Literal(literal) = dot_receiver.clone()
&& let Some(literal_text) = ast::String::cast(literal.token())
{
add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text);
@@ -379,14 +388,22 @@ fn escape_snippet_bits(text: &mut String) {
stdx::replace(text, '$', "\\$");
}
+fn receiver_accessor(receiver: &ast::Expr) -> ast::Expr {
+ receiver
+ .syntax()
+ .parent()
+ .and_then(ast::Expr::cast)
+ .filter(|it| {
+ matches!(
+ it,
+ ast::Expr::FieldExpr(_) | ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_)
+ )
+ })
+ .unwrap_or_else(|| receiver.clone())
+}
+
fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
let mut resulting_element = initial_element.clone();
-
- while let Some(field_expr) = resulting_element.syntax().parent().and_then(ast::FieldExpr::cast)
- {
- resulting_element = ast::Expr::from(field_expr);
- }
-
let mut prefix = String::new();
let mut found_ref_or_deref = false;
@@ -672,6 +689,87 @@ fn main() {
sn while while expr {}
"#]],
);
+ check(
+ r#"
+fn main() {
+ &baz.l$0
+ res
+}
+"#,
+ expect![[r#"
+ sn box Box::new(expr)
+ sn call function(expr)
+ sn const const {}
+ sn dbg dbg!(expr)
+ sn dbgr dbg!(&expr)
+ sn deref *expr
+ sn if if expr {}
+ sn let let
+ sn letm let mut
+ sn match match expr {}
+ sn not !expr
+ sn ref &expr
+ sn refm &mut expr
+ sn return return expr
+ sn unsafe unsafe {}
+ sn while while expr {}
+ "#]],
+ );
+ }
+
+ #[test]
+ fn let_tail_block() {
+ check(
+ r#"
+fn main() {
+ baz.l$0
+}
+"#,
+ expect![[r#"
+ sn box Box::new(expr)
+ sn call function(expr)
+ sn const const {}
+ sn dbg dbg!(expr)
+ sn dbgr dbg!(&expr)
+ sn deref *expr
+ sn if if expr {}
+ sn let let
+ sn letm let mut
+ sn match match expr {}
+ sn not !expr
+ sn ref &expr
+ sn refm &mut expr
+ sn return return expr
+ sn unsafe unsafe {}
+ sn while while expr {}
+ "#]],
+ );
+
+ check(
+ r#"
+fn main() {
+ &baz.l$0
+}
+"#,
+ expect![[r#"
+ sn box Box::new(expr)
+ sn call function(expr)
+ sn const const {}
+ sn dbg dbg!(expr)
+ sn dbgr dbg!(&expr)
+ sn deref *expr
+ sn if if expr {}
+ sn let let
+ sn letm let mut
+ sn match match expr {}
+ sn not !expr
+ sn ref &expr
+ sn refm &mut expr
+ sn return return expr
+ sn unsafe unsafe {}
+ sn while while expr {}
+ "#]],
+ );
}
#[test]
@@ -796,6 +894,78 @@ fn main() {
}
#[test]
+ fn match_arm_let_block() {
+ check(
+ r#"
+fn main() {
+ match 2 {
+ bar => bar.$0
+ }
+}
+"#,
+ expect![[r#"
+ sn box Box::new(expr)
+ sn call function(expr)
+ sn const const {}
+ sn dbg dbg!(expr)
+ sn dbgr dbg!(&expr)
+ sn deref *expr
+ sn let let
+ sn letm let mut
+ sn match match expr {}
+ sn ref &expr
+ sn refm &mut expr
+ sn return return expr
+ sn unsafe unsafe {}
+ "#]],
+ );
+ check(
+ r#"
+fn main() {
+ match 2 {
+ bar => &bar.l$0
+ }
+}
+"#,
+ expect![[r#"
+ sn box Box::new(expr)
+ sn call function(expr)
+ sn const const {}
+ sn dbg dbg!(expr)
+ sn dbgr dbg!(&expr)
+ sn deref *expr
+ sn let let
+ sn letm let mut
+ sn match match expr {}
+ sn ref &expr
+ sn refm &mut expr
+ sn return return expr
+ sn unsafe unsafe {}
+ "#]],
+ );
+ check_edit(
+ "let",
+ r#"
+fn main() {
+ match 2 {
+ bar => bar.$0
+ }
+}
+"#,
+ r#"
+fn main() {
+ match 2 {
+ bar => {
+ let $1 = bar;
+ $0
+}
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
fn option_letelse() {
check_edit(
"lete",