about summary refs log tree commit diff
path: root/crates
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-06-03 15:20:30 +0000
committerbors <bors@rust-lang.org>2022-06-03 15:20:30 +0000
commitd06d0f8774b3f07f9d269264f2f7eefaac459ca7 (patch)
tree78d6cdc69d054ee30dcfede8ef58d14ab7d6df86 /crates
parentd0a7ad4a7f10239f5d800bc3a336a6fa24fef2ce (diff)
parent2a60b8452e469f8002834a7ac14a29434d92f12b (diff)
downloadrust-d06d0f8774b3f07f9d269264f2f7eefaac459ca7.tar.gz
rust-d06d0f8774b3f07f9d269264f2f7eefaac459ca7.zip
Auto merge of #12459 - Veykril:completions, r=Veykril
internal: Clean up keyword completion handling

https://github.com/rust-lang/rust-analyzer/issues/12144
Diffstat (limited to 'crates')
-rw-r--r--crates/ide-completion/src/completions.rs21
-rw-r--r--crates/ide-completion/src/completions/expr.rs10
-rw-r--r--crates/ide-completion/src/completions/field.rs33
-rw-r--r--crates/ide-completion/src/completions/flyimport.rs13
-rw-r--r--crates/ide-completion/src/completions/item_list.rs86
-rw-r--r--crates/ide-completion/src/completions/keyword.rs115
-rw-r--r--crates/ide-completion/src/completions/type.rs9
-rw-r--r--crates/ide-completion/src/context.rs135
-rw-r--r--crates/ide-completion/src/lib.rs1
-rw-r--r--crates/ide-completion/src/patterns.rs160
-rw-r--r--crates/ide-completion/src/render.rs2
-rw-r--r--crates/ide-completion/src/render/function.rs2
-rw-r--r--crates/ide-completion/src/tests/item.rs86
-rw-r--r--crates/ide-completion/src/tests/item_list.rs13
-rw-r--r--crates/ide-completion/src/tests/record.rs1
15 files changed, 291 insertions, 396 deletions
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 931b92dec3f..b6358d4f40c 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -4,6 +4,7 @@ pub(crate) mod attribute;
 pub(crate) mod dot;
 pub(crate) mod expr;
 pub(crate) mod extern_abi;
+pub(crate) mod field;
 pub(crate) mod flyimport;
 pub(crate) mod fn_param;
 pub(crate) mod format_string;
@@ -110,6 +111,26 @@ impl Completions {
         ["self", "super", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
     }
 
+    pub(crate) fn add_keyword_snippet(&mut self, ctx: &CompletionContext, kw: &str, snippet: &str) {
+        let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
+
+        match ctx.config.snippet_cap {
+            Some(cap) => {
+                if snippet.ends_with('}') && ctx.incomplete_let {
+                    // complete block expression snippets with a trailing semicolon, if inside an incomplete let
+                    cov_mark::hit!(let_semi);
+                    item.insert_snippet(cap, format!("{};", snippet));
+                } else {
+                    item.insert_snippet(cap, snippet);
+                }
+            }
+            None => {
+                item.insert_text(if snippet.contains('$') { kw } else { snippet });
+            }
+        };
+        item.add_to(self);
+    }
+
     pub(crate) fn add_crate_roots(&mut self, ctx: &CompletionContext) {
         ctx.process_all_names(&mut |name, res| match res {
             ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index ae7b42e3056..23f47523d66 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -15,12 +15,12 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
         return;
     }
 
-    let (is_absolute_path, qualifier, in_block_expr, in_loop_body, is_func_update) =
+    let (is_absolute_path, qualifier, in_block_expr, in_loop_body, is_func_update, after_if_expr) =
         match ctx.nameref_ctx() {
             Some(NameRefContext {
                 path_ctx:
                     Some(PathCompletionCtx {
-                        kind: PathKind::Expr { in_block_expr, in_loop_body },
+                        kind: PathKind::Expr { in_block_expr, in_loop_body, after_if_expr },
                         is_absolute_path,
                         qualifier,
                         ..
@@ -33,6 +33,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
                 *in_block_expr,
                 *in_loop_body,
                 record_expr.as_ref().map_or(false, |&(_, it)| it),
+                *after_if_expr,
             ),
             _ => return,
         };
@@ -177,8 +178,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
             });
 
             if !is_func_update {
-                let mut add_keyword =
-                    |kw, snippet| super::keyword::add_keyword(acc, ctx, kw, snippet);
+                let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
 
                 if ctx.expects_expression() {
                     if !in_block_expr {
@@ -202,7 +202,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
                     add_keyword("let", "let");
                 }
 
-                if ctx.after_if() {
+                if after_if_expr {
                     add_keyword("else", "else {\n    $0\n}");
                     add_keyword("else if", "else if $1 {\n    $0\n}");
                 }
diff --git a/crates/ide-completion/src/completions/field.rs b/crates/ide-completion/src/completions/field.rs
new file mode 100644
index 00000000000..17395279178
--- /dev/null
+++ b/crates/ide-completion/src/completions/field.rs
@@ -0,0 +1,33 @@
+//! Completion of field list position.
+
+use crate::{
+    context::{IdentContext, NameContext, NameKind, NameRefContext, PathCompletionCtx, PathKind},
+    CompletionContext, Completions,
+};
+
+pub(crate) fn complete_field_list(acc: &mut Completions, ctx: &CompletionContext) {
+    match &ctx.ident_ctx {
+        IdentContext::Name(NameContext { kind: NameKind::RecordField, .. })
+        | IdentContext::NameRef(NameRefContext {
+            path_ctx:
+                Some(PathCompletionCtx {
+                    has_macro_bang: false,
+                    is_absolute_path: false,
+                    qualifier: None,
+                    parent: None,
+                    kind: PathKind::Type { in_tuple_struct: true },
+                    has_type_args: false,
+                    ..
+                }),
+            ..
+        }) => {
+            if ctx.qualifier_ctx.vis_node.is_none() {
+                let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
+                add_keyword("pub(crate)", "pub(crate)");
+                add_keyword("pub(super)", "pub(super)");
+                add_keyword("pub", "pub");
+            }
+        }
+        _ => return,
+    }
+}
diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs
index 873db300b84..22068096ba0 100644
--- a/crates/ide-completion/src/completions/flyimport.rs
+++ b/crates/ide-completion/src/completions/flyimport.rs
@@ -110,10 +110,8 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
     if !ctx.config.enable_imports_on_the_fly {
         return None;
     }
-    if matches!(ctx.path_kind(), Some(PathKind::Vis { .. } | PathKind::Use))
+    if matches!(ctx.path_kind(), Some(PathKind::Vis { .. } | PathKind::Use | PathKind::Item { .. }))
         || ctx.is_path_disallowed()
-        || ctx.expects_item()
-        || ctx.expects_assoc_item()
     {
         return None;
     }
@@ -160,7 +158,10 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
             (_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
             // and so are macros(except for attributes)
             (
-                PathKind::Expr { .. } | PathKind::Type | PathKind::Item { .. } | PathKind::Pat,
+                PathKind::Expr { .. }
+                | PathKind::Type { .. }
+                | PathKind::Item { .. }
+                | PathKind::Pat,
                 ItemInNs::Macros(mac),
             ) => mac.is_fn_like(ctx.db),
             (PathKind::Item { .. }, _) => true,
@@ -170,14 +171,14 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
             (PathKind::Pat, ItemInNs::Types(_)) => true,
             (PathKind::Pat, ItemInNs::Values(def)) => matches!(def, hir::ModuleDef::Const(_)),
 
-            (PathKind::Type, ItemInNs::Types(ty)) => {
+            (PathKind::Type { .. }, ItemInNs::Types(ty)) => {
                 if matches!(ctx.completion_location, Some(ImmediateLocation::TypeBound)) {
                     matches!(ty, ModuleDef::Trait(_))
                 } else {
                     true
                 }
             }
-            (PathKind::Type, ItemInNs::Values(_)) => false,
+            (PathKind::Type { .. }, ItemInNs::Values(_)) => false,
 
             (PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db),
             (PathKind::Attr { .. }, _) => false,
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs
index edff146d8d7..287cf46f2e3 100644
--- a/crates/ide-completion/src/completions/item_list.rs
+++ b/crates/ide-completion/src/completions/item_list.rs
@@ -2,22 +2,98 @@
 
 use crate::{
     completions::module_or_fn_macro,
-    context::{PathCompletionCtx, PathKind, PathQualifierCtx},
+    context::{ItemListKind, PathCompletionCtx, PathKind, PathQualifierCtx},
     CompletionContext, Completions,
 };
 
 pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext) {
     let _p = profile::span("complete_item_list");
 
-    let (&is_absolute_path, path_qualifier, _kind) = match ctx.path_context() {
+    let (&is_absolute_path, path_qualifier, kind) = match ctx.path_context() {
         Some(PathCompletionCtx {
             kind: PathKind::Item { kind },
             is_absolute_path,
             qualifier,
             ..
-        }) => (is_absolute_path, qualifier, kind),
+        }) => (is_absolute_path, qualifier, Some(kind)),
+        Some(PathCompletionCtx {
+            kind: PathKind::Expr { in_block_expr: true, .. },
+            is_absolute_path,
+            qualifier,
+            ..
+        }) => (is_absolute_path, qualifier, None),
         _ => return,
     };
+    let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
+
+    let in_item_list = matches!(kind, Some(ItemListKind::SourceFile | ItemListKind::Module) | None);
+    let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait));
+    let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock));
+    let in_trait = matches!(kind, Some(ItemListKind::Trait));
+    let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl));
+    let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl));
+    let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
+    let in_block = matches!(kind, None);
+
+    'block: loop {
+        if ctx.is_non_trivial_path() {
+            break 'block;
+        }
+        if !in_trait_impl {
+            if ctx.qualifier_ctx.unsafe_tok.is_some() {
+                if in_item_list || in_assoc_non_trait_impl {
+                    add_keyword("fn", "fn $1($2) {\n    $0\n}");
+                }
+                if in_item_list {
+                    add_keyword("trait", "trait $1 {\n    $0\n}");
+                    if no_qualifiers {
+                        add_keyword("impl", "impl $1 {\n    $0\n}");
+                    }
+                }
+                break 'block;
+            }
+
+            if in_item_list {
+                add_keyword("enum", "enum $1 {\n    $0\n}");
+                add_keyword("mod", "mod $0");
+                add_keyword("static", "static $0");
+                add_keyword("struct", "struct $0");
+                add_keyword("trait", "trait $1 {\n    $0\n}");
+                add_keyword("union", "union $1 {\n    $0\n}");
+                add_keyword("use", "use $0");
+                if no_qualifiers {
+                    add_keyword("impl", "impl $1 {\n    $0\n}");
+                }
+            }
+
+            if !in_trait && !in_block && no_qualifiers {
+                add_keyword("pub(crate)", "pub(crate)");
+                add_keyword("pub(super)", "pub(super)");
+                add_keyword("pub", "pub");
+            }
+
+            if in_extern_block {
+                add_keyword("fn", "fn $1($2);");
+            } else {
+                if !in_inherent_impl {
+                    if !in_trait {
+                        add_keyword("extern", "extern $0");
+                    }
+                    add_keyword("type", "type $0");
+                }
+
+                add_keyword("fn", "fn $1($2) {\n    $0\n}");
+                add_keyword("unsafe", "unsafe");
+                add_keyword("const", "const $0");
+            }
+        }
+        break 'block;
+    }
+
+    if kind.is_none() {
+        // this is already handled by expression
+        return;
+    }
 
     match path_qualifier {
         Some(PathQualifierCtx { resolution, is_super_chain, .. }) => {
@@ -33,9 +109,7 @@ pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext)
                 acc.add_keyword(ctx, "super::");
             }
         }
-        None if is_absolute_path => {
-            acc.add_crate_roots(ctx);
-        }
+        None if is_absolute_path => acc.add_crate_roots(ctx),
         None if ctx.qualifier_ctx.none() => {
             ctx.process_all_names(&mut |name, def| {
                 if let Some(def) = module_or_fn_macro(ctx.db, def) {
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 281e6e9783c..e870ecc2295 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -2,106 +2,39 @@
 //! - `self`, `super` and `crate`, as these are considered part of path completions.
 //! - `await`, as this is a postfix completion we handle this in the postfix completions.
 
-use syntax::T;
+use syntax::ast::Item;
 
-use crate::{
-    context::{NameRefContext, PathKind},
-    CompletionContext, CompletionItem, CompletionItemKind, Completions,
-};
+use crate::{context::NameRefContext, CompletionContext, Completions};
 
 pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
-    if matches!(ctx.nameref_ctx(), Some(NameRefContext { record_expr: Some(_), .. })) {
-        cov_mark::hit!(no_keyword_completion_in_record_lit);
-        return;
-    }
-    if ctx.is_non_trivial_path() {
-        cov_mark::hit!(no_keyword_completion_in_non_trivial_path);
-        return;
-    }
-    if ctx.pattern_ctx.is_some() {
-        return;
-    }
-
-    let mut add_keyword = |kw, snippet| add_keyword(acc, ctx, kw, snippet);
-
-    let expects_assoc_item = ctx.expects_assoc_item();
-    let has_block_expr_parent = ctx.has_block_expr_parent();
-    let expects_item = ctx.expects_item();
-
-    if let Some(PathKind::Vis { .. }) = ctx.path_kind() {
-        return;
-    }
-    if ctx.has_unfinished_impl_or_trait_prev_sibling() {
-        add_keyword("where", "where");
-        if ctx.has_impl_prev_sibling() {
-            add_keyword("for", "for");
-        }
-        return;
-    }
-    if ctx.previous_token_is(T![unsafe]) {
-        if expects_item || expects_assoc_item || has_block_expr_parent {
-            add_keyword("fn", "fn $1($2) {\n    $0\n}")
+    let item = match ctx.nameref_ctx() {
+        Some(NameRefContext { keyword: Some(item), record_expr: None, .. })
+            if !ctx.is_non_trivial_path() =>
+        {
+            item
         }
+        _ => return,
+    };
 
-        if expects_item || has_block_expr_parent {
-            add_keyword("trait", "trait $1 {\n    $0\n}");
-            add_keyword("impl", "impl $1 {\n    $0\n}");
-        }
-
-        return;
-    }
-
-    if ctx.qualifier_ctx.vis_node.is_none()
-        && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field())
-    {
-        add_keyword("pub(crate)", "pub(crate)");
-        add_keyword("pub(super)", "pub(super)");
-        add_keyword("pub", "pub");
-    }
-
-    if expects_item || expects_assoc_item || has_block_expr_parent {
-        add_keyword("unsafe", "unsafe");
-        add_keyword("fn", "fn $1($2) {\n    $0\n}");
-        add_keyword("const", "const $0");
-        add_keyword("type", "type $0");
-    }
-
-    if expects_item || has_block_expr_parent {
-        if ctx.qualifier_ctx.vis_node.is_none() {
-            add_keyword("impl", "impl $1 {\n    $0\n}");
-            add_keyword("extern", "extern $0");
-        }
-        add_keyword("use", "use $0");
-        add_keyword("trait", "trait $1 {\n    $0\n}");
-        add_keyword("static", "static $0");
-        add_keyword("mod", "mod $0");
-    }
-
-    if expects_item || has_block_expr_parent {
-        add_keyword("enum", "enum $1 {\n    $0\n}");
-        add_keyword("struct", "struct $0");
-        add_keyword("union", "union $1 {\n    $0\n}");
-    }
-}
-
-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);
+    let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
 
-    match ctx.config.snippet_cap {
-        Some(cap) => {
-            if snippet.ends_with('}') && ctx.incomplete_let {
-                // complete block expression snippets with a trailing semicolon, if inside an incomplete let
-                cov_mark::hit!(let_semi);
-                item.insert_snippet(cap, format!("{};", snippet));
-            } else {
-                item.insert_snippet(cap, snippet);
+    match item {
+        Item::Impl(it) => {
+            if it.for_token().is_none() && it.trait_().is_none() && it.self_ty().is_some() {
+                add_keyword("for", "for");
             }
+            add_keyword("where", "where");
         }
-        None => {
-            item.insert_text(if snippet.contains('$') { kw } else { snippet });
+        Item::Enum(_)
+        | Item::Fn(_)
+        | Item::Struct(_)
+        | Item::Trait(_)
+        | Item::TypeAlias(_)
+        | Item::Union(_) => {
+            add_keyword("where", "where");
         }
-    };
-    item.add_to(acc);
+        _ => (),
+    }
 }
 
 #[cfg(test)]
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index 91414c8bf6a..bc8c070c14d 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -18,9 +18,12 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
     }
 
     let (&is_absolute_path, qualifier) = match ctx.path_context() {
-        Some(PathCompletionCtx { kind: PathKind::Type, is_absolute_path, qualifier, .. }) => {
-            (is_absolute_path, qualifier)
-        }
+        Some(PathCompletionCtx {
+            kind: PathKind::Type { .. },
+            is_absolute_path,
+            qualifier,
+            ..
+        }) => (is_absolute_path, qualifier),
         _ => return,
     };
 
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index f3e316ff3c1..6068a9eb32c 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -15,7 +15,7 @@ use ide_db::{
 use syntax::{
     algo::{find_node_at_offset, non_trivia_sibling},
     ast::{self, AttrKind, HasArgList, HasName, NameOrNameRef},
-    match_ast, AstNode, AstToken, NodeOrToken,
+    match_ast, AstNode, AstToken, Direction, NodeOrToken,
     SyntaxKind::{self, *},
     SyntaxNode, SyntaxToken, TextRange, TextSize, T,
 };
@@ -23,8 +23,8 @@ use text_edit::Indel;
 
 use crate::{
     patterns::{
-        determine_location, determine_prev_sibling, is_in_loop_body, is_in_token_of_for_loop,
-        previous_token, ImmediateLocation, ImmediatePrevSibling,
+        determine_location, is_in_loop_body, is_in_token_of_for_loop, previous_token,
+        ImmediateLocation,
     },
     CompletionConfig,
 };
@@ -48,8 +48,11 @@ pub(super) enum PathKind {
     Expr {
         in_block_expr: bool,
         in_loop_body: bool,
+        after_if_expr: bool,
+    },
+    Type {
+        in_tuple_struct: bool,
     },
-    Type,
     Attr {
         kind: AttrKind,
         annotated_item_kind: Option<SyntaxKind>,
@@ -71,6 +74,7 @@ pub(super) enum ItemListKind {
     SourceFile,
     Module,
     Impl,
+    TraitImpl,
     Trait,
     ExternBlock,
 }
@@ -182,6 +186,8 @@ pub(super) struct NameRefContext {
     // FIXME: these fields are actually disjoint -> enum
     pub(super) dot_access: Option<DotAccess>,
     pub(super) path_ctx: Option<PathCompletionCtx>,
+    /// Position where we are only interested in keyword completions
+    pub(super) keyword: Option<ast::Item>,
     /// The record expression this nameref is a field of
     pub(super) record_expr: Option<(ast::RecordExpr, bool)>,
 }
@@ -259,7 +265,6 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) incomplete_let: bool,
 
     pub(super) completion_location: Option<ImmediateLocation>,
-    pub(super) prev_sibling: Option<ImmediatePrevSibling>,
     pub(super) previous_token: Option<SyntaxToken>,
 
     pub(super) ident_ctx: IdentContext,
@@ -331,55 +336,15 @@ impl<'a> CompletionContext<'a> {
         self.dot_receiver().is_some()
     }
 
-    pub(crate) fn expects_assoc_item(&self) -> bool {
-        matches!(self.completion_location, Some(ImmediateLocation::Trait | ImmediateLocation::Impl))
-    }
-
-    pub(crate) fn expects_non_trait_assoc_item(&self) -> bool {
-        matches!(self.completion_location, Some(ImmediateLocation::Impl))
-    }
-
-    pub(crate) fn expects_item(&self) -> bool {
-        matches!(self.completion_location, Some(ImmediateLocation::ItemList))
-    }
-
     // FIXME: This shouldn't exist
     pub(crate) fn expects_generic_arg(&self) -> bool {
         matches!(self.completion_location, Some(ImmediateLocation::GenericArgList(_)))
     }
 
-    pub(crate) fn has_block_expr_parent(&self) -> bool {
-        matches!(self.completion_location, Some(ImmediateLocation::StmtList))
-    }
-
     pub(crate) fn expects_ident_ref_expr(&self) -> bool {
         matches!(self.completion_location, Some(ImmediateLocation::RefExpr))
     }
 
-    pub(crate) fn expect_field(&self) -> bool {
-        matches!(self.completion_location, Some(ImmediateLocation::TupleField))
-            || matches!(self.name_ctx(), Some(NameContext { kind: NameKind::RecordField, .. }))
-    }
-
-    /// Whether the cursor is right after a trait or impl header.
-    /// trait Foo ident$0
-    // FIXME: This probably shouldn't exist
-    pub(crate) fn has_unfinished_impl_or_trait_prev_sibling(&self) -> bool {
-        matches!(
-            self.prev_sibling,
-            Some(ImmediatePrevSibling::ImplDefType | ImmediatePrevSibling::TraitDefName)
-        )
-    }
-
-    // FIXME: This probably shouldn't exist
-    pub(crate) fn has_impl_prev_sibling(&self) -> bool {
-        matches!(self.prev_sibling, Some(ImmediatePrevSibling::ImplDefType))
-    }
-
-    pub(crate) fn after_if(&self) -> bool {
-        matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr))
-    }
-
     // FIXME: This shouldn't exist
     pub(crate) fn is_path_disallowed(&self) -> bool {
         !self.qualifier_ctx.none()
@@ -558,7 +523,6 @@ impl<'a> CompletionContext<'a> {
             impl_def: None,
             incomplete_let: false,
             completion_location: None,
-            prev_sibling: None,
             previous_token: None,
             // dummy value, will be overwritten
             ident_ctx: IdentContext::UnexpandedAttrTT { fake_attribute_under_caret: None },
@@ -953,7 +917,6 @@ impl<'a> CompletionContext<'a> {
         };
         self.completion_location =
             determine_location(&self.sema, original_file, offset, &name_like);
-        self.prev_sibling = determine_prev_sibling(&name_like);
         self.impl_def = self
             .sema
             .token_ancestors_with_macros(self.token.clone())
@@ -1110,8 +1073,13 @@ impl<'a> CompletionContext<'a> {
     ) -> (NameRefContext, Option<PatternContext>) {
         let nameref = find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
 
-        let mut nameref_ctx =
-            NameRefContext { dot_access: None, path_ctx: None, nameref, record_expr: None };
+        let mut nameref_ctx = NameRefContext {
+            dot_access: None,
+            path_ctx: None,
+            nameref,
+            record_expr: None,
+            keyword: None,
+        };
 
         if let Some(record_field) = ast::RecordExprField::for_field_name(&name_ref) {
             nameref_ctx.record_expr =
@@ -1195,6 +1163,13 @@ impl<'a> CompletionContext<'a> {
                     find_node_in_file_compensated(original_file, &record_expr).zip(Some(true));
             }
         };
+        let after_if_expr = |node: SyntaxNode| {
+            let prev_expr = (|| {
+                let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
+                ast::ExprStmt::cast(prev_sibling)?.expr()
+            })();
+            matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
+        };
 
         // We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
         // ex. trait Foo $0 {}
@@ -1208,7 +1183,7 @@ impl<'a> CompletionContext<'a> {
                 syntax::algo::non_trivia_sibling(node.into(), syntax::Direction::Prev)
             {
                 if let Some(item) = ast::Item::cast(n) {
-                    match item {
+                    let is_inbetween = match &item {
                         ast::Item::Const(it) => it.body().is_none(),
                         ast::Item::Enum(it) => it.variant_list().is_none(),
                         ast::Item::ExternBlock(it) => it.extern_item_list().is_none(),
@@ -1221,24 +1196,27 @@ impl<'a> CompletionContext<'a> {
                         ast::Item::TypeAlias(it) => it.ty().is_none(),
                         ast::Item::Union(it) => it.record_field_list().is_none(),
                         _ => false,
+                    };
+                    if is_inbetween {
+                        return Some(item);
                     }
-                } else {
-                    false
                 }
-            } else {
-                false
             }
+            None
         };
 
         let kind = path.syntax().ancestors().find_map(|it| {
             // using Option<Option<PathKind>> as extra controlflow
             let kind = match_ast! {
                 match it {
-                    ast::PathType(_) => Some(PathKind::Type),
+                    ast::PathType(it) => Some(PathKind::Type {
+                        in_tuple_struct: it.syntax().parent().map_or(false, |it| ast::TupleField::can_cast(it.kind()))
+                    }),
                     ast::PathExpr(it) => {
                         if let Some(p) = it.syntax().parent() {
                             if ast::ExprStmt::can_cast(p.kind()) {
-                                if inbetween_body_and_decl_check(p) {
+                                if let Some(kind) = inbetween_body_and_decl_check(p) {
+                                    nameref_ctx.keyword = Some(kind);
                                     return Some(None);
                                 }
                             }
@@ -1249,7 +1227,9 @@ 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 after_if_expr = after_if_expr(it.syntax().clone());
+
+                        Some(PathKind::Expr { in_block_expr, in_loop_body, after_if_expr })
                     },
                     ast::TupleStructPat(it) => {
                         path_ctx.has_call_parens = true;
@@ -1266,7 +1246,8 @@ impl<'a> CompletionContext<'a> {
                         Some(PathKind::Pat)
                     },
                     ast::MacroCall(it) => {
-                        if inbetween_body_and_decl_check(it.syntax().clone()) {
+                        if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
+                            nameref_ctx.keyword = Some(kind);
                             return Some(None);
                         }
 
@@ -1274,12 +1255,21 @@ impl<'a> CompletionContext<'a> {
                         let parent = it.syntax().parent();
                         match parent.as_ref().map(|it| it.kind()) {
                             Some(SyntaxKind::MACRO_PAT) => Some(PathKind::Pat),
-                            Some(SyntaxKind::MACRO_TYPE) => Some(PathKind::Type),
+                            Some(SyntaxKind::MACRO_TYPE) => Some(PathKind::Type { in_tuple_struct: false }),
                             Some(SyntaxKind::ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::Module }),
-                            Some(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()).map(|it| it.kind()) {
-                                Some(SyntaxKind::TRAIT) => ItemListKind::Trait,
-                                Some(SyntaxKind::IMPL) => ItemListKind::Impl,
-                                _ => return Some(None),
+                            Some(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()) {
+                                Some(it) => match_ast! {
+                                    match it {
+                                        ast::Trait(_) => ItemListKind::Trait,
+                                        ast::Impl(it) => if it.trait_().is_some() {
+                                            ItemListKind::TraitImpl
+                                        } else {
+                                            ItemListKind::Impl
+                                        },
+                                        _ => return Some(None)
+                                    }
+                                },
+                                None => return Some(None),
                             } }),
                             Some(SyntaxKind::EXTERN_ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::ExternBlock }),
                             Some(SyntaxKind::SOURCE_FILE) => Some(PathKind::Item { kind: ItemListKind::SourceFile }),
@@ -1287,8 +1277,9 @@ 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());
+                                    let after_if_expr = after_if_expr(it.syntax().clone());
                                     fill_record_expr(it.syntax());
-                                    PathKind::Expr { in_block_expr, in_loop_body }
+                                    PathKind::Expr { in_block_expr, in_loop_body, after_if_expr }
                                 }));
                             },
                         }
@@ -1313,12 +1304,18 @@ impl<'a> CompletionContext<'a> {
                     ast::UseTree(_) => Some(PathKind::Use),
                     ast::ItemList(_) => Some(PathKind::Item { kind: ItemListKind::Module }),
                     ast::AssocItemList(it) => Some(PathKind::Item { kind: {
-                            match it.syntax().parent()?.kind() {
-                                SyntaxKind::TRAIT => ItemListKind::Trait,
-                                SyntaxKind::IMPL => ItemListKind::Impl,
-                                _ => return None,
+                        match_ast! {
+                            match (it.syntax().parent()?) {
+                                ast::Trait(_) => ItemListKind::Trait,
+                                ast::Impl(it) => if it.trait_().is_some() {
+                                    ItemListKind::TraitImpl
+                                } else {
+                                    ItemListKind::Impl
+                                },
+                                _ => return None
                             }
-                        }}),
+                        }
+                    }}),
                     ast::ExternItemList(_) => Some(PathKind::Item { kind: ItemListKind::ExternBlock }),
                     ast::SourceFile(_) => Some(PathKind::Item { kind: ItemListKind::SourceFile }),
                     _ => return None,
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 9659efad619..c100dd63eac 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -158,6 +158,7 @@ pub fn completions(
             completions::dot::complete_dot(acc, ctx);
             completions::expr::complete_expr_path(acc, ctx);
             completions::extern_abi::complete_extern_abi(acc, ctx);
+            completions::field::complete_field_list(acc, ctx);
             completions::flyimport::import_on_the_fly(acc, ctx);
             completions::fn_param::complete_fn_param(acc, ctx);
             completions::format_string::format_string(acc, ctx);
diff --git a/crates/ide-completion/src/patterns.rs b/crates/ide-completion/src/patterns.rs
index cc599a02cb2..9abbfaa4072 100644
--- a/crates/ide-completion/src/patterns.rs
+++ b/crates/ide-completion/src/patterns.rs
@@ -7,9 +7,8 @@
 use hir::Semantics;
 use ide_db::RootDatabase;
 use syntax::{
-    algo::non_trivia_sibling,
     ast::{self, HasLoopBody, HasName},
-    match_ast, AstNode, Direction, SyntaxElement,
+    match_ast, AstNode, SyntaxElement,
     SyntaxKind::*,
     SyntaxNode, SyntaxToken, TextRange, TextSize,
 };
@@ -17,14 +16,6 @@ use syntax::{
 #[cfg(test)]
 use crate::tests::check_pattern_is_applicable;
 
-/// Immediate previous node to what we are completing.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub(crate) enum ImmediatePrevSibling {
-    IfExpr,
-    TraitDefName,
-    ImplDefType,
-}
-
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum TypeAnnotation {
     Let(Option<ast::Pat>),
@@ -39,13 +30,7 @@ pub(crate) enum TypeAnnotation {
 /// from which file the nodes are.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ImmediateLocation {
-    Impl,
-    Trait,
-    TupleField,
     RefExpr,
-    IdentPat,
-    StmtList,
-    ItemList,
     TypeBound,
     /// Original file ast node
     TypeAnnotation(TypeAnnotation),
@@ -54,56 +39,6 @@ pub(crate) enum ImmediateLocation {
     GenericArgList(ast::GenericArgList),
 }
 
-pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<ImmediatePrevSibling> {
-    let node = match name_like {
-        ast::NameLike::NameRef(name_ref) => maximize_name_ref(name_ref),
-        ast::NameLike::Name(n) => n.syntax().clone(),
-        ast::NameLike::Lifetime(lt) => lt.syntax().clone(),
-    };
-    let node = match node.parent().and_then(ast::MacroCall::cast) {
-        // When a path is being typed after the name of a trait/type of an impl it is being
-        // parsed as a macro, so when the trait/impl has a block following it an we are between the
-        // name and block the macro will attach the block to itself so maximizing fails to take
-        // that into account
-        // FIXME path expr and statement have a similar problem with attrs
-        Some(call)
-            if call.excl_token().is_none()
-                && call.token_tree().map_or(false, |t| t.l_curly_token().is_some())
-                && call.semicolon_token().is_none() =>
-        {
-            call.syntax().clone()
-        }
-        _ => node,
-    };
-    let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
-    let res = match_ast! {
-        match prev_sibling {
-            ast::ExprStmt(it) => {
-                let node = it.expr().filter(|_| it.semicolon_token().is_none())?.syntax().clone();
-                match_ast! {
-                    match node {
-                        ast::IfExpr(_) => ImmediatePrevSibling::IfExpr,
-                        _ => return None,
-                    }
-                }
-            },
-            ast::Trait(it) => if it.assoc_item_list().is_none() {
-                    ImmediatePrevSibling::TraitDefName
-                } else {
-                    return None
-            },
-            ast::Impl(it) => if it.assoc_item_list().is_none()
-                && (it.for_token().is_none() || it.self_ty().is_some()) {
-                    ImmediatePrevSibling::ImplDefType
-                } else {
-                    return None
-            },
-            _ => return None,
-        }
-    };
-    Some(res)
-}
-
 pub(crate) fn determine_location(
     sema: &Semantics<RootDatabase>,
     original_file: &SyntaxNode,
@@ -140,30 +75,14 @@ pub(crate) fn determine_location(
             _ => parent,
         },
         // SourceFile
-        None => {
-            return match node.kind() {
-                MACRO_ITEMS | SOURCE_FILE => Some(ImmediateLocation::ItemList),
-                _ => None,
-            }
-        }
+        None => return None,
     };
 
     let res = match_ast! {
         match parent {
-            ast::IdentPat(_) => ImmediateLocation::IdentPat,
-            ast::StmtList(_) => ImmediateLocation::StmtList,
-            ast::SourceFile(_) => ImmediateLocation::ItemList,
-            ast::ItemList(_) => ImmediateLocation::ItemList,
             ast::RefExpr(_) => ImmediateLocation::RefExpr,
-            ast::TupleField(_) => ImmediateLocation::TupleField,
-            ast::TupleFieldList(_) => ImmediateLocation::TupleField,
             ast::TypeBound(_) => ImmediateLocation::TypeBound,
             ast::TypeBoundList(_) => ImmediateLocation::TypeBound,
-            ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) {
-                Some(IMPL) => ImmediateLocation::Impl,
-                Some(TRAIT) => ImmediateLocation::Trait,
-                _ => return None,
-            },
             ast::GenericArgList(_) => sema
                 .find_node_at_offset_with_macros(original_file, offset)
                 .map(ImmediateLocation::GenericArgList)?,
@@ -351,83 +270,8 @@ mod tests {
         );
     }
 
-    fn check_prev_sibling(code: &str, sibling: impl Into<Option<ImmediatePrevSibling>>) {
-        check_pattern_is_applicable(code, |e| {
-            let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike");
-            assert_eq!(determine_prev_sibling(name), sibling.into());
-            true
-        });
-    }
-
-    #[test]
-    fn test_trait_loc() {
-        check_location(r"trait A { f$0 }", ImmediateLocation::Trait);
-        check_location(r"trait A { #[attr] f$0 }", ImmediateLocation::Trait);
-        check_location(r"trait A { f$0 fn f() {} }", ImmediateLocation::Trait);
-        check_location(r"trait A { fn f() {} f$0 }", ImmediateLocation::Trait);
-        check_location(r"trait A$0 {}", None);
-        check_location(r"trait A { fn f$0 }", None);
-    }
-
-    #[test]
-    fn test_impl_loc() {
-        check_location(r"impl A { f$0 }", ImmediateLocation::Impl);
-        check_location(r"impl A { #[attr] f$0 }", ImmediateLocation::Impl);
-        check_location(r"impl A { f$0 fn f() {} }", ImmediateLocation::Impl);
-        check_location(r"impl A { fn f() {} f$0 }", ImmediateLocation::Impl);
-        check_location(r"impl A$0 {}", None);
-        check_location(r"impl A { fn f$0 }", None);
-    }
-
-    #[test]
-    fn test_block_expr_loc() {
-        check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::StmtList);
-        check_location(r"fn my_fn() { f$0 f }", ImmediateLocation::StmtList);
-    }
-
-    #[test]
-    fn test_ident_pat_loc() {
-        check_location(r"fn my_fn(m$0) {}", ImmediateLocation::IdentPat);
-        check_location(r"fn my_fn() { let m$0 }", ImmediateLocation::IdentPat);
-        check_location(r"fn my_fn(&m$0) {}", ImmediateLocation::IdentPat);
-        check_location(r"fn my_fn() { let &m$0 }", ImmediateLocation::IdentPat);
-    }
-
     #[test]
     fn test_ref_expr_loc() {
         check_location(r"fn my_fn() { let x = &m$0 foo; }", ImmediateLocation::RefExpr);
     }
-
-    #[test]
-    fn test_item_list_loc() {
-        check_location(r"i$0", ImmediateLocation::ItemList);
-        check_location(r"#[attr] i$0", ImmediateLocation::ItemList);
-        check_location(r"fn f() {} i$0", ImmediateLocation::ItemList);
-        check_location(r"mod foo { f$0 }", ImmediateLocation::ItemList);
-        check_location(r"mod foo { #[attr] f$0 }", ImmediateLocation::ItemList);
-        check_location(r"mod foo { fn f() {} f$0 }", ImmediateLocation::ItemList);
-        check_location(r"mod foo$0 {}", None);
-    }
-
-    #[test]
-    fn test_impl_prev_sibling() {
-        check_prev_sibling(r"impl A w$0 ", ImmediatePrevSibling::ImplDefType);
-        check_prev_sibling(r"impl A w$0 {}", ImmediatePrevSibling::ImplDefType);
-        check_prev_sibling(r"impl A for A w$0 ", ImmediatePrevSibling::ImplDefType);
-        check_prev_sibling(r"impl A for A w$0 {}", ImmediatePrevSibling::ImplDefType);
-        check_prev_sibling(r"impl A for w$0 {}", None);
-        check_prev_sibling(r"impl A for w$0", None);
-    }
-
-    #[test]
-    fn test_trait_prev_sibling() {
-        check_prev_sibling(r"trait A w$0 ", ImmediatePrevSibling::TraitDefName);
-        check_prev_sibling(r"trait A w$0 {}", ImmediatePrevSibling::TraitDefName);
-    }
-
-    #[test]
-    fn test_if_expr_prev_sibling() {
-        check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr);
-        check_prev_sibling(r"fn foo() { if true {}; w$0", None);
-    }
 }
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index d51bc517d65..ca2b3ad3435 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -286,7 +286,7 @@ fn render_resolution_simple_(
     // Add `<>` for generic types
     let type_path_no_ty_args = matches!(
         ctx.completion.path_context(),
-        Some(PathCompletionCtx { kind: PathKind::Type, has_type_args: false, .. })
+        Some(PathCompletionCtx { kind: PathKind::Type { .. }, has_type_args: false, .. })
     ) && ctx.completion.config.callable.is_some();
     if type_path_no_ty_args {
         if let Some(cap) = ctx.snippet_cap() {
diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs
index 5e1fbfa4a21..0be51b0e3ff 100644
--- a/crates/ide-completion/src/render/function.rs
+++ b/crates/ide-completion/src/render/function.rs
@@ -202,7 +202,7 @@ fn should_add_parens(ctx: &CompletionContext) -> bool {
         Some(PathCompletionCtx { kind: PathKind::Expr { .. }, has_call_parens: true, .. }) => {
             return false
         }
-        Some(PathCompletionCtx { kind: PathKind::Use | PathKind::Type, .. }) => {
+        Some(PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. }) => {
             cov_mark::hit!(no_parens_in_use_item);
             return false;
         }
diff --git a/crates/ide-completion/src/tests/item.rs b/crates/ide-completion/src/tests/item.rs
index 537c9a7fa24..81303eb38f4 100644
--- a/crates/ide-completion/src/tests/item.rs
+++ b/crates/ide-completion/src/tests/item.rs
@@ -76,65 +76,65 @@ fn after_target_name_in_impl() {
             kw where
         "#]],
     );
-    // FIXME: This should not emit `kw for`
     check(
-        r"impl Trait for Type $0",
+        r"impl Trait f$0",
         expect![[r#"
             kw for
             kw where
         "#]],
     );
-}
-
-#[test]
-fn after_struct_name() {
-    // FIXME: This should emit `kw where` only
     check(
-        r"struct Struct $0",
+        r"impl Trait for Type $0",
         expect![[r#"
-            kw const
-            kw enum
-            kw extern
-            kw fn
-            kw impl
-            kw mod
-            kw pub
-            kw pub(crate)
-            kw pub(super)
-            kw static
-            kw struct
-            kw trait
-            kw type
-            kw union
-            kw unsafe
-            kw use
+            kw where
         "#]],
     );
 }
 
 #[test]
-fn after_fn_name() {
-    // FIXME: This should emit `kw where` only
+fn completes_where() {
+    check(
+        r"struct Struct $0",
+        expect![[r#"
+        kw where
+    "#]],
+    );
+    check(
+        r"struct Struct $0 {}",
+        expect![[r#"
+        kw where
+    "#]],
+    );
+    // FIXME: This shouldn't be completed here
+    check(
+        r"struct Struct $0 ()",
+        expect![[r#"
+        kw where
+    "#]],
+    );
     check(
         r"fn func() $0",
         expect![[r#"
-            kw const
-            kw enum
-            kw extern
-            kw fn
-            kw impl
-            kw mod
-            kw pub
-            kw pub(crate)
-            kw pub(super)
-            kw static
-            kw struct
-            kw trait
-            kw type
-            kw union
-            kw unsafe
-            kw use
-        "#]],
+        kw where
+    "#]],
+    );
+    check(
+        r"enum Enum $0",
+        expect![[r#"
+        kw where
+    "#]],
+    );
+    check(
+        r"enum Enum $0 {}",
+        expect![[r#"
+        kw where
+    "#]],
+    );
+    check(
+        r"trait Trait $0 {}",
+        expect![[r#"
+        kw where
+    "#]],
     );
 }
 
diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs
index d03a4fd5cd1..09ea78a3d50 100644
--- a/crates/ide-completion/src/tests/item_list.rs
+++ b/crates/ide-completion/src/tests/item_list.rs
@@ -108,7 +108,6 @@ fn in_item_list_after_attr() {
 
 #[test]
 fn in_qualified_path() {
-    cov_mark::check!(no_keyword_completion_in_non_trivial_path);
     check(
         r#"crate::$0"#,
         expect![[r#"
@@ -137,6 +136,7 @@ fn after_visibility() {
         expect![[r#"
             kw const
             kw enum
+            kw extern
             kw fn
             kw mod
             kw static
@@ -152,12 +152,10 @@ fn after_visibility() {
 
 #[test]
 fn after_visibility_unsafe() {
-    // FIXME this shouldn't show `impl`
     check(
         r#"pub unsafe $0"#,
         expect![[r#"
             kw fn
-            kw impl
             kw trait
         "#]],
     );
@@ -178,7 +176,6 @@ fn in_impl_assoc_item_list() {
             kw pub(super)
             kw self::
             kw super::
-            kw type
             kw unsafe
         "#]],
     )
@@ -199,7 +196,6 @@ fn in_impl_assoc_item_list_after_attr() {
             kw pub(super)
             kw self::
             kw super::
-            kw type
             kw unsafe
         "#]],
     )
@@ -249,16 +245,9 @@ impl Test for () {
             ma makro!(…)          macro_rules! makro
             md module
             ta type Type1 =
-            kw const
             kw crate::
-            kw fn
-            kw pub
-            kw pub(crate)
-            kw pub(super)
             kw self::
             kw super::
-            kw type
-            kw unsafe
         "#]],
     );
 }
diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs
index 9e442dbbc56..9369034cc62 100644
--- a/crates/ide-completion/src/tests/record.rs
+++ b/crates/ide-completion/src/tests/record.rs
@@ -9,7 +9,6 @@ fn check(ra_fixture: &str, expect: Expect) {
 
 #[test]
 fn without_default_impl() {
-    cov_mark::check!(no_keyword_completion_in_record_lit);
     check(
         r#"
 struct Struct { foo: u32, bar: usize }