about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/ide-completion/src/completions/expr.rs78
-rw-r--r--crates/ide-completion/src/completions/fn_param.rs1
-rw-r--r--crates/ide-completion/src/completions/keyword.rs73
-rw-r--r--crates/ide-completion/src/completions/trait_impl.rs1
-rw-r--r--crates/ide-completion/src/completions/vis.rs2
-rw-r--r--crates/ide-completion/src/context.rs15
-rw-r--r--crates/ide-completion/src/lib.rs2
-rw-r--r--crates/ide-completion/src/tests/record.rs11
8 files changed, 84 insertions, 99 deletions
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index a2a17d92185..87fae18f4cd 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -2,6 +2,7 @@
 
 use hir::ScopeDef;
 use ide_db::FxHashSet;
+use syntax::T;
 
 use crate::{
     context::{PathCompletionCtx, PathKind, PathQualifierCtx},
@@ -14,15 +15,16 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
         return;
     }
 
-    let (&is_absolute_path, qualifier) = match ctx.path_context() {
-        Some(PathCompletionCtx {
-            kind: PathKind::Expr { .. },
-            is_absolute_path,
-            qualifier,
-            ..
-        }) => (is_absolute_path, qualifier),
-        _ => return,
-    };
+    let (is_absolute_path, qualifier, in_block_expr, in_loop_body, in_functional_update) =
+        match ctx.path_context() {
+            Some(&PathCompletionCtx {
+                kind: PathKind::Expr { in_block_expr, in_loop_body, in_functional_update },
+                is_absolute_path,
+                ref qualifier,
+                ..
+            }) => (is_absolute_path, qualifier, in_block_expr, in_loop_body, in_functional_update),
+            _ => return,
+        };
 
     let scope_def_applicable = |def| {
         use hir::{GenericParam::*, ModuleDef::*};
@@ -162,6 +164,64 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
                     acc.add_resolution(ctx, name, def);
                 }
             });
+
+            if !in_functional_update {
+                let mut add_keyword =
+                    |kw, snippet| super::keyword::add_keyword(acc, ctx, kw, snippet);
+
+                if ctx.expects_expression() {
+                    if !in_block_expr {
+                        add_keyword("unsafe", "unsafe {\n    $0\n}");
+                    }
+                    add_keyword("match", "match $1 {\n    $0\n}");
+                    add_keyword("while", "while $1 {\n    $0\n}");
+                    add_keyword("while let", "while let $1 = $2 {\n    $0\n}");
+                    add_keyword("loop", "loop {\n    $0\n}");
+                    add_keyword("if", "if $1 {\n    $0\n}");
+                    add_keyword("if let", "if let $1 = $2 {\n    $0\n}");
+                    add_keyword("for", "for $1 in $2 {\n    $0\n}");
+                    add_keyword("true", "true");
+                    add_keyword("false", "false");
+                }
+
+                if ctx.previous_token_is(T![if])
+                    || ctx.previous_token_is(T![while])
+                    || in_block_expr
+                {
+                    add_keyword("let", "let");
+                }
+
+                if ctx.after_if() {
+                    add_keyword("else", "else {\n    $0\n}");
+                    add_keyword("else if", "else if $1 {\n    $0\n}");
+                }
+
+                if ctx.expects_ident_ref_expr() {
+                    add_keyword("mut", "mut ");
+                }
+
+                if in_loop_body {
+                    if in_block_expr {
+                        add_keyword("continue", "continue;");
+                        add_keyword("break", "break;");
+                    } else {
+                        add_keyword("continue", "continue");
+                        add_keyword("break", "break");
+                    }
+                }
+
+                if let Some(fn_def) = &ctx.function_def {
+                    add_keyword(
+                        "return",
+                        match (in_block_expr, fn_def.ret_type().is_some()) {
+                            (true, true) => "return ;",
+                            (true, false) => "return;",
+                            (false, true) => "return $0",
+                            (false, false) => "return",
+                        },
+                    );
+                }
+            }
         }
     }
 }
diff --git a/crates/ide-completion/src/completions/fn_param.rs b/crates/ide-completion/src/completions/fn_param.rs
index 47cead7d570..0cdb8ee1190 100644
--- a/crates/ide-completion/src/completions/fn_param.rs
+++ b/crates/ide-completion/src/completions/fn_param.rs
@@ -13,6 +13,7 @@ use crate::{
     CompletionContext, CompletionItem, CompletionItemKind, Completions,
 };
 
+// FIXME: Make this a submodule of [`pattern`]
 /// Complete repeated parameters, both name and type. For example, if all
 /// functions in a file have a `spam: &mut Spam` parameter, a completion with
 /// `spam: &mut Spam` insert text/label will be suggested.
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index b34545414ec..14211f86baa 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -5,9 +5,8 @@
 use syntax::T;
 
 use crate::{
-    context::{PathCompletionCtx, PathKind},
-    patterns::ImmediateLocation,
-    CompletionContext, CompletionItem, CompletionItemKind, Completions,
+    context::PathKind, patterns::ImmediateLocation, CompletionContext, CompletionItem,
+    CompletionItemKind, Completions,
 };
 
 pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
@@ -83,75 +82,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
         add_keyword("struct", "struct $0");
         add_keyword("union", "union $1 {\n    $0\n}");
     }
-
-    if ctx.expects_type() {
-        return;
-    }
-
-    if ctx.expects_expression() {
-        if !has_block_expr_parent {
-            add_keyword("unsafe", "unsafe {\n    $0\n}");
-        }
-        add_keyword("match", "match $1 {\n    $0\n}");
-        add_keyword("while", "while $1 {\n    $0\n}");
-        add_keyword("while let", "while let $1 = $2 {\n    $0\n}");
-        add_keyword("loop", "loop {\n    $0\n}");
-        add_keyword("if", "if $1 {\n    $0\n}");
-        add_keyword("if let", "if let $1 = $2 {\n    $0\n}");
-        add_keyword("for", "for $1 in $2 {\n    $0\n}");
-        add_keyword("true", "true");
-        add_keyword("false", "false");
-    }
-
-    if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent {
-        add_keyword("let", "let");
-    }
-
-    if ctx.after_if() {
-        add_keyword("else", "else {\n    $0\n}");
-        add_keyword("else if", "else if $1 {\n    $0\n}");
-    }
-
-    if ctx.expects_ident_ref_expr() {
-        add_keyword("mut", "mut ");
-    }
-
-    let (can_be_stmt, in_loop_body) = match ctx.path_context() {
-        Some(&PathCompletionCtx {
-            is_absolute_path: false,
-            kind: PathKind::Expr { in_block_expr, in_loop_body, .. },
-            ..
-        }) => (in_block_expr, in_loop_body),
-        _ => return,
-    };
-
-    if in_loop_body {
-        if can_be_stmt {
-            add_keyword("continue", "continue;");
-            add_keyword("break", "break;");
-        } else {
-            add_keyword("continue", "continue");
-            add_keyword("break", "break");
-        }
-    }
-
-    let fn_def = match &ctx.function_def {
-        Some(it) => it,
-        None => return,
-    };
-
-    add_keyword(
-        "return",
-        match (can_be_stmt, fn_def.ret_type().is_some()) {
-            (true, true) => "return $0;",
-            (true, false) => "return;",
-            (false, true) => "return $0",
-            (false, false) => "return",
-        },
-    )
 }
 
-fn add_keyword(acc: &mut Completions, ctx: &CompletionContext, kw: &str, snippet: &str) {
+pub(super) fn add_keyword(acc: &mut Completions, ctx: &CompletionContext, kw: &str, snippet: &str) {
     let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
 
     match ctx.config.snippet_cap {
diff --git a/crates/ide-completion/src/completions/trait_impl.rs b/crates/ide-completion/src/completions/trait_impl.rs
index e3c15038d07..61c5d126493 100644
--- a/crates/ide-completion/src/completions/trait_impl.rs
+++ b/crates/ide-completion/src/completions/trait_impl.rs
@@ -52,6 +52,7 @@ enum ImplCompletionKind {
     Const,
 }
 
+// FIXME: Make this a submodule of [`item_list`]
 pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
     if let Some((kind, replacement_range, impl_def)) = completion_match(ctx) {
         if let Some(hir_impl) = ctx.sema.to_def(&impl_def) {
diff --git a/crates/ide-completion/src/completions/vis.rs b/crates/ide-completion/src/completions/vis.rs
index b5e86b62d1a..d538f1879e7 100644
--- a/crates/ide-completion/src/completions/vis.rs
+++ b/crates/ide-completion/src/completions/vis.rs
@@ -7,7 +7,7 @@ use crate::{
     Completions,
 };
 
-pub(crate) fn complete_vis(acc: &mut Completions, ctx: &CompletionContext) {
+pub(crate) fn complete_vis_path(acc: &mut Completions, ctx: &CompletionContext) {
     let (&is_absolute_path, qualifier, &has_in_token) = match ctx.path_context() {
         Some(PathCompletionCtx {
             kind: PathKind::Vis { has_in_token },
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index f6b8962df63..4a058ac2619 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -48,6 +48,7 @@ pub(super) enum PathKind {
     Expr {
         in_block_expr: bool,
         in_loop_body: bool,
+        in_functional_update: bool,
     },
     Type,
     Attr {
@@ -392,10 +393,6 @@ impl<'a> CompletionContext<'a> {
         matches!(self.path_context(), Some(PathCompletionCtx { kind: PathKind::Expr { .. }, .. }))
     }
 
-    pub(crate) fn expects_type(&self) -> bool {
-        matches!(self.path_context(), Some(PathCompletionCtx { kind: PathKind::Type, .. }))
-    }
-
     pub(crate) fn is_non_trivial_path(&self) -> bool {
         matches!(
             self.path_context(),
@@ -1104,6 +1101,9 @@ impl<'a> CompletionContext<'a> {
                 })
                 .unwrap_or(false)
         };
+        let is_in_func_update = |it: &SyntaxNode| {
+            it.parent().map_or(false, |it| ast::RecordExprFieldList::can_cast(it.kind()))
+        };
 
         let kind = path.syntax().ancestors().find_map(|it| {
             // using Option<Option<PathKind>> as extra controlflow
@@ -1114,8 +1114,8 @@ impl<'a> CompletionContext<'a> {
                         path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
                         let in_block_expr = is_in_block(it.syntax());
                         let in_loop_body = is_in_loop_body(it.syntax());
-
-                        Some(PathKind::Expr { in_block_expr, in_loop_body })
+                        let in_functional_update = is_in_func_update(it.syntax());
+                        Some(PathKind::Expr { in_block_expr, in_loop_body, in_functional_update })
                     },
                     ast::TupleStructPat(it) => {
                         path_ctx.has_call_parens = true;
@@ -1149,7 +1149,8 @@ impl<'a> CompletionContext<'a> {
                                return Some(parent.and_then(ast::MacroExpr::cast).map(|it| {
                                     let in_loop_body = is_in_loop_body(it.syntax());
                                     let in_block_expr = is_in_block(it.syntax());
-                                    PathKind::Expr { in_block_expr, in_loop_body }
+                                    let in_functional_update = is_in_func_update(it.syntax());
+                                    PathKind::Expr { in_block_expr, in_loop_body, in_functional_update }
                                 }));
                             },
                         }
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 6695fcdc192..7789c967070 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -173,7 +173,7 @@ pub fn completions(
         completions::r#type::complete_type_path(acc, ctx);
         completions::r#type::complete_inferred_type(acc, ctx);
         completions::use_::complete_use_tree(acc, ctx);
-        completions::vis::complete_vis(acc, ctx);
+        completions::vis::complete_vis_path(acc, ctx);
     }
 
     Some(acc)
diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs
index a0f8b248672..2c497617484 100644
--- a/crates/ide-completion/src/tests/record.rs
+++ b/crates/ide-completion/src/tests/record.rs
@@ -168,19 +168,8 @@ fn main() {
             tt Sized
             bt u32
             kw crate::
-            kw false
-            kw for
-            kw if
-            kw if let
-            kw loop
-            kw match
-            kw return
             kw self::
             kw super::
-            kw true
-            kw unsafe
-            kw while
-            kw while let
         "#]],
     );
     check(