about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/ide-completion/src/completions/attribute.rs33
-rw-r--r--crates/ide-completion/src/completions/attribute/derive.rs27
-rw-r--r--crates/ide-completion/src/completions/dot.rs32
-rw-r--r--crates/ide-completion/src/completions/expr.rs19
-rw-r--r--crates/ide-completion/src/completions/extern_abi.rs22
-rw-r--r--crates/ide-completion/src/completions/field.rs34
-rw-r--r--crates/ide-completion/src/completions/fn_param.rs10
-rw-r--r--crates/ide-completion/src/completions/format_string.rs27
-rw-r--r--crates/ide-completion/src/completions/item_list.rs69
-rw-r--r--crates/ide-completion/src/completions/item_list/trait_impl.rs117
-rw-r--r--crates/ide-completion/src/completions/keyword.rs24
-rw-r--r--crates/ide-completion/src/completions/lifetime.rs22
-rw-r--r--crates/ide-completion/src/completions/mod_.rs10
-rw-r--r--crates/ide-completion/src/completions/pattern.rs34
-rw-r--r--crates/ide-completion/src/completions/postfix.rs21
-rw-r--r--crates/ide-completion/src/completions/record.rs129
-rw-r--r--crates/ide-completion/src/completions/snippet.rs24
-rw-r--r--crates/ide-completion/src/completions/type.rs37
-rw-r--r--crates/ide-completion/src/completions/use_.rs21
-rw-r--r--crates/ide-completion/src/completions/vis.rs36
-rw-r--r--crates/ide-completion/src/context.rs22
-rw-r--r--crates/ide-completion/src/lib.rs121
-rw-r--r--crates/ide-completion/src/render.rs22
-rw-r--r--crates/ide-completion/src/render/function.rs96
-rw-r--r--crates/ide-completion/src/render/literal.rs23
-rw-r--r--crates/ide-completion/src/render/macro_.rs11
-rw-r--r--crates/ide-completion/src/render/pattern.rs11
-rw-r--r--crates/ide-completion/src/tests/record.rs2
-rw-r--r--crates/ide-completion/src/tests/use_tree.rs1
29 files changed, 602 insertions, 455 deletions
diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs
index fe5bdeec662..992d7eabd8a 100644
--- a/crates/ide-completion/src/completions/attribute.rs
+++ b/crates/ide-completion/src/completions/attribute.rs
@@ -18,7 +18,7 @@ use syntax::{
 
 use crate::{
     completions::module_or_attr,
-    context::{CompletionContext, IdentContext, PathCompletionCtx, PathKind, Qualified},
+    context::{CompletionContext, PathCompletionCtx, PathKind, Qualified},
     item::CompletionItem,
     Completions,
 };
@@ -34,11 +34,9 @@ pub(crate) use self::derive::complete_derive;
 pub(crate) fn complete_known_attribute_input(
     acc: &mut Completions,
     ctx: &CompletionContext,
+    fake_attribute_under_caret: &ast::Attr,
 ) -> Option<()> {
-    let attribute = match &ctx.ident_ctx {
-        IdentContext::UnexpandedAttrTT { fake_attribute_under_caret: Some(it) } => it,
-        _ => return None,
-    };
+    let attribute = fake_attribute_under_caret;
     let name_ref = match attribute.path() {
         Some(p) => Some(p.as_single_name_ref()?),
         None => None,
@@ -71,27 +69,30 @@ pub(crate) fn complete_known_attribute_input(
     Some(())
 }
 
-pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) {
-    let (qualified, is_inner, annotated_item_kind) = match ctx.path_context() {
-        Some(&PathCompletionCtx {
+pub(crate) fn complete_attribute(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+) {
+    let (qualified, is_inner, annotated_item_kind) = match path_ctx {
+        &PathCompletionCtx {
             kind: PathKind::Attr { kind, annotated_item_kind },
             ref qualified,
             ..
-        }) => (qualified, kind == AttrKind::Inner, annotated_item_kind),
+        } => (qualified, kind == AttrKind::Inner, annotated_item_kind),
         _ => return,
     };
 
     match qualified {
-        Qualified::With { resolution, is_super_chain, .. } => {
+        Qualified::With {
+            resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
+            is_super_chain,
+            ..
+        } => {
             if *is_super_chain {
                 acc.add_keyword(ctx, "super::");
             }
 
-            let module = match resolution {
-                Some(hir::PathResolution::Def(hir::ModuleDef::Module(it))) => it,
-                _ => return,
-            };
-
             for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
                 if let Some(def) = module_or_attr(ctx.db, def) {
                     acc.add_resolution(ctx, name, def);
@@ -110,7 +111,7 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer => {}
+        Qualified::Infer | Qualified::With { .. } => {}
     }
 
     let attributes = annotated_item_kind.and_then(|kind| {
diff --git a/crates/ide-completion/src/completions/attribute/derive.rs b/crates/ide-completion/src/completions/attribute/derive.rs
index aefb986535e..0927d2f7643 100644
--- a/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/crates/ide-completion/src/completions/attribute/derive.rs
@@ -10,27 +10,30 @@ use crate::{
     Completions,
 };
 
-pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
-    let (qualified, existing_derives) = match ctx.path_context() {
-        Some(PathCompletionCtx {
-            kind: PathKind::Derive { existing_derives }, qualified, ..
-        }) => (qualified, existing_derives),
+pub(crate) fn complete_derive(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+) {
+    let (qualified, existing_derives) = match path_ctx {
+        PathCompletionCtx { kind: PathKind::Derive { existing_derives }, qualified, .. } => {
+            (qualified, existing_derives)
+        }
         _ => return,
     };
 
     let core = ctx.famous_defs().core();
 
     match qualified {
-        Qualified::With { resolution, is_super_chain, .. } => {
+        Qualified::With {
+            resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
+            is_super_chain,
+            ..
+        } => {
             if *is_super_chain {
                 acc.add_keyword(ctx, "super::");
             }
 
-            let module = match resolution {
-                Some(hir::PathResolution::Def(hir::ModuleDef::Module(it))) => it,
-                _ => return,
-            };
-
             for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
                 let add_def = match def {
                     ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
@@ -101,7 +104,7 @@ pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer => {}
+        Qualified::Infer | Qualified::With { .. } => {}
     }
 }
 
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index bdafdf4152e..a315d616d55 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -4,21 +4,16 @@ use ide_db::FxHashSet;
 
 use crate::{
     context::{
-        CompletionContext, DotAccess, DotAccessKind, NameRefContext, NameRefKind,
-        PathCompletionCtx, PathKind, Qualified,
+        CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind, Qualified,
     },
     CompletionItem, CompletionItemKind, Completions,
 };
 
 /// Complete dot accesses, i.e. fields or methods.
-pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
-    let (dot_access, receiver_ty) = match ctx.nameref_ctx() {
-        Some(NameRefContext {
-            kind:
-                Some(NameRefKind::DotAccess(access @ DotAccess { receiver_ty: Some(receiver_ty), .. })),
-            ..
-        }) => (access, &receiver_ty.original),
-        _ => return complete_undotted_self(acc, ctx),
+pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext, dot_access: &DotAccess) {
+    let receiver_ty = match dot_access {
+        DotAccess { receiver_ty: Some(receiver_ty), .. } => &receiver_ty.original,
+        _ => return,
     };
 
     // Suggest .await syntax for types that implement Future trait
@@ -43,18 +38,17 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
     complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, func, None, None));
 }
 
-fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) {
+pub(crate) fn complete_undotted_self(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+) {
     if !ctx.config.enable_self_on_the_fly {
         return;
     }
-    match ctx.path_context() {
-        Some(
-            path_ctx @ PathCompletionCtx {
-                qualified: Qualified::No,
-                kind: PathKind::Expr { .. },
-                ..
-            },
-        ) if path_ctx.is_trivial_path() && ctx.qualifier_ctx.none() => {}
+    match path_ctx {
+        PathCompletionCtx { qualified: Qualified::No, kind: PathKind::Expr { .. }, .. }
+            if path_ctx.is_trivial_path() && ctx.qualifier_ctx.none() => {}
         _ => return,
     }
 
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index fcd2144809e..afc929d68d8 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -8,7 +8,11 @@ use crate::{
     CompletionContext, Completions,
 };
 
-pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext) {
+pub(crate) fn complete_expr_path(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name_ref_ctx: &NameRefContext,
+) {
     let _p = profile::span("complete_expr_path");
 
     let (
@@ -19,8 +23,8 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
         after_if_expr,
         wants_mut_token,
         in_condition,
-    ) = match ctx.nameref_ctx() {
-        Some(&NameRefContext {
+    ) = match name_ref_ctx {
+        &NameRefContext {
             kind:
                 Some(NameRefKind::Path(PathCompletionCtx {
                     kind:
@@ -36,7 +40,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
                     ..
                 })),
             ..
-        }) if ctx.qualifier_ctx.none() => (
+        } if ctx.qualifier_ctx.none() => (
             qualified,
             in_block_expr,
             in_loop_body,
@@ -65,11 +69,8 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
             .into_iter()
             .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, ctx, item)),
-        Qualified::With { resolution, .. } => {
-            let resolution = match resolution {
-                Some(it) => it,
-                None => return,
-            };
+        Qualified::With { resolution: None, .. } => {}
+        Qualified::With { resolution: Some(resolution), .. } => {
             // Add associated types on type parameters and `Self`.
             ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
                 acc.add_type_alias(ctx, alias);
diff --git a/crates/ide-completion/src/completions/extern_abi.rs b/crates/ide-completion/src/completions/extern_abi.rs
index ae8c199f0c4..3007b3c319c 100644
--- a/crates/ide-completion/src/completions/extern_abi.rs
+++ b/crates/ide-completion/src/completions/extern_abi.rs
@@ -5,9 +5,7 @@ use syntax::{
 };
 
 use crate::{
-    completions::Completions,
-    context::{CompletionContext, IdentContext},
-    CompletionItem, CompletionItemKind,
+    completions::Completions, context::CompletionContext, CompletionItem, CompletionItemKind,
 };
 
 // Most of these are feature gated, we should filter/add feature gate completions once we have them.
@@ -42,15 +40,15 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[
     "unadjusted",
 ];
 
-pub(crate) fn complete_extern_abi(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
-    let abi_str = match &ctx.ident_ctx {
-        IdentContext::String { expanded: Some(expanded), .. }
-            if expanded.syntax().parent().map_or(false, |it| ast::Abi::can_cast(it.kind())) =>
-        {
-            expanded
-        }
-        _ => return None,
-    };
+pub(crate) fn complete_extern_abi(
+    acc: &mut Completions,
+    _ctx: &CompletionContext,
+    expanded: &ast::String,
+) -> Option<()> {
+    if !expanded.syntax().parent().map_or(false, |it| ast::Abi::can_cast(it.kind())) {
+        return None;
+    }
+    let abi_str = expanded;
     let source_range = abi_str.text_range_between_quotes()?;
     for &abi in SUPPORTED_CALLING_CONVENTIONS {
         CompletionItem::new(CompletionItemKind::Keyword, source_range, abi).add_to(acc);
diff --git a/crates/ide-completion/src/completions/field.rs b/crates/ide-completion/src/completions/field.rs
index a9f598fffd3..93263f61cf1 100644
--- a/crates/ide-completion/src/completions/field.rs
+++ b/crates/ide-completion/src/completions/field.rs
@@ -2,16 +2,19 @@
 
 use crate::{
     context::{
-        IdentContext, NameContext, NameKind, NameRefContext, NameRefKind, PathCompletionCtx,
-        PathKind, Qualified, TypeLocation,
+        NameContext, NameKind, NameRefContext, NameRefKind, PathCompletionCtx, PathKind, Qualified,
+        TypeLocation,
     },
     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 {
+pub(crate) fn complete_field_list_tuple_variant(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name_ref_ctx: &NameRefContext,
+) {
+    match name_ref_ctx {
+        NameRefContext {
             kind:
                 Some(NameRefKind::Path(PathCompletionCtx {
                     has_macro_bang: false,
@@ -22,7 +25,7 @@ pub(crate) fn complete_field_list(acc: &mut Completions, ctx: &CompletionContext
                     ..
                 })),
             ..
-        }) => {
+        } => {
             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)");
@@ -30,6 +33,21 @@ pub(crate) fn complete_field_list(acc: &mut Completions, ctx: &CompletionContext
                 add_keyword("pub", "pub");
             }
         }
-        _ => return,
+        _ => (),
+    }
+}
+
+pub(crate) fn complete_field_list_record_variant(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name_ctx: &NameContext,
+) {
+    if let NameContext { kind: NameKind::RecordField, .. } = name_ctx {
+        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");
+        }
     }
 }
diff --git a/crates/ide-completion/src/completions/fn_param.rs b/crates/ide-completion/src/completions/fn_param.rs
index 67648ac17b5..a62b966e019 100644
--- a/crates/ide-completion/src/completions/fn_param.rs
+++ b/crates/ide-completion/src/completions/fn_param.rs
@@ -19,9 +19,13 @@ use crate::{
 /// `spam: &mut Spam` insert text/label will be suggested.
 ///
 /// Also complete parameters for closure or local functions from the surrounding defined locals.
-pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
-    let (param_list, _, param_kind) = match &ctx.pattern_ctx {
-        Some(PatternContext { param_ctx: Some(kind), .. }) => kind,
+pub(crate) fn complete_fn_param(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    pattern_ctx: &PatternContext,
+) -> Option<()> {
+    let (param_list, _, param_kind) = match pattern_ctx {
+        PatternContext { param_ctx: Some(kind), .. } => kind,
         _ => return None,
     };
 
diff --git a/crates/ide-completion/src/completions/format_string.rs b/crates/ide-completion/src/completions/format_string.rs
index 132599906af..f7a75b2dd58 100644
--- a/crates/ide-completion/src/completions/format_string.rs
+++ b/crates/ide-completion/src/completions/format_string.rs
@@ -2,28 +2,25 @@
 
 use ide_db::syntax_helpers::format_string::is_format_string;
 use itertools::Itertools;
-use syntax::{AstToken, TextRange, TextSize};
+use syntax::{ast, AstToken, TextRange, TextSize};
 
-use crate::{
-    context::{CompletionContext, IdentContext},
-    CompletionItem, CompletionItemKind, Completions,
-};
+use crate::{context::CompletionContext, CompletionItem, CompletionItemKind, Completions};
 
 /// Complete identifiers in format strings.
-pub(crate) fn format_string(acc: &mut Completions, ctx: &CompletionContext) {
-    let string = match &ctx.ident_ctx {
-        IdentContext::String { expanded: Some(expanded), original }
-            if is_format_string(&expanded) =>
-        {
-            original
-        }
-        _ => return,
-    };
+pub(crate) fn format_string(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    original: &ast::String,
+    expanded: &ast::String,
+) {
+    if !is_format_string(&expanded) {
+        return;
+    }
     let cursor = ctx.position.offset;
     let lit_start = ctx.original_token.text_range().start();
     let cursor_in_lit = cursor - lit_start;
 
-    let prefix = &string.text()[..cursor_in_lit.into()];
+    let prefix = &original.text()[..cursor_in_lit.into()];
     let braces = prefix.char_indices().rev().skip_while(|&(_, c)| c.is_alphanumeric()).next_tuple();
     let brace_offset = match braces {
         // escaped brace
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs
index 2e03935086d..e613f2d25b1 100644
--- a/crates/ide-completion/src/completions/item_list.rs
+++ b/crates/ide-completion/src/completions/item_list.rs
@@ -2,54 +2,63 @@
 
 use crate::{
     completions::module_or_fn_macro,
-    context::{ItemListKind, PathCompletionCtx, PathKind, Qualified},
+    context::{ItemListKind, NameRefContext, NameRefKind, PathCompletionCtx, PathKind, Qualified},
     CompletionContext, Completions,
 };
 
-mod trait_impl;
+pub(crate) mod trait_impl;
 
-pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext) {
+pub(crate) fn complete_item_list(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name_ref_ctx: &NameRefContext,
+) {
     let _p = profile::span("complete_item_list");
 
-    if let Some(_) = ctx.name_ctx() {
-        trait_impl::complete_trait_impl(acc, ctx);
-        return;
-    }
-
-    let (qualified, kind, is_trivial_path) = match ctx.path_context() {
-        Some(ctx @ PathCompletionCtx { kind: PathKind::Item { kind }, qualified, .. }) => {
-            (qualified, Some(kind), ctx.is_trivial_path())
-        }
-        Some(
-            ctx @ PathCompletionCtx {
-                kind: PathKind::Expr { in_block_expr: true, .. },
-                qualified,
-                ..
-            },
-        ) => (qualified, None, ctx.is_trivial_path()),
+    let (qualified, item_list_kind, is_trivial_path) = match name_ref_ctx {
+        NameRefContext {
+            kind:
+                Some(NameRefKind::Path(
+                    ctx @ PathCompletionCtx { kind: PathKind::Item { kind }, qualified, .. },
+                )),
+            ..
+        } => (qualified, Some(kind), ctx.is_trivial_path()),
+        NameRefContext {
+            kind:
+                Some(NameRefKind::Path(
+                    ctx @ PathCompletionCtx {
+                        kind: PathKind::Expr { in_block_expr: true, .. },
+                        qualified,
+                        ..
+                    },
+                )),
+            ..
+        } => (qualified, None, ctx.is_trivial_path()),
         _ => return,
     };
 
-    if matches!(kind, Some(ItemListKind::TraitImpl)) {
-        trait_impl::complete_trait_impl(acc, ctx);
+    if matches!(item_list_kind, Some(ItemListKind::TraitImpl)) {
+        trait_impl::complete_trait_impl_name_ref(acc, ctx, name_ref_ctx);
     }
 
     if is_trivial_path {
-        add_keywords(acc, ctx, kind);
+        add_keywords(acc, ctx, item_list_kind);
     }
 
-    if kind.is_none() {
+    if item_list_kind.is_none() {
         // this is already handled by expression
         return;
     }
 
     match qualified {
-        Qualified::With { resolution, is_super_chain, .. } => {
-            if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) = resolution {
-                for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
-                    if let Some(def) = module_or_fn_macro(ctx.db, def) {
-                        acc.add_resolution(ctx, name, def);
-                    }
+        Qualified::With {
+            resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
+            is_super_chain,
+            ..
+        } => {
+            for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
+                if let Some(def) = module_or_fn_macro(ctx.db, def) {
+                    acc.add_resolution(ctx, name, def);
                 }
             }
 
@@ -66,7 +75,7 @@ pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext)
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::No => {}
+        Qualified::Infer | Qualified::No | Qualified::With { .. } => {}
     }
 }
 
diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 846d5f09028..701985d507d 100644
--- a/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -44,8 +44,8 @@ use text_edit::TextEdit;
 
 use crate::{
     context::{
-        IdentContext, ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind,
-        PathCompletionCtx, PathKind,
+        ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind, PathCompletionCtx,
+        PathKind,
     },
     CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, Completions,
 };
@@ -58,53 +58,41 @@ enum ImplCompletionKind {
     Const,
 }
 
-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) {
-            get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| {
-                use self::ImplCompletionKind::*;
-                match (item, kind) {
-                    (hir::AssocItem::Function(func), All | Fn) => {
-                        add_function_impl(acc, ctx, replacement_range, func, hir_impl)
-                    }
-                    (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => {
-                        add_type_alias_impl(acc, ctx, replacement_range, type_alias)
-                    }
-                    (hir::AssocItem::Const(const_), All | Const) => {
-                        add_const_impl(acc, ctx, replacement_range, const_, hir_impl)
-                    }
-                    _ => {}
-                }
-            });
-        }
-    }
+pub(crate) fn complete_trait_impl_name(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    NameContext { name, kind, .. }: &NameContext,
+) -> Option<()> {
+    let kind = match kind {
+        NameKind::Const => ImplCompletionKind::Const,
+        NameKind::Function => ImplCompletionKind::Fn,
+        NameKind::TypeAlias => ImplCompletionKind::TypeAlias,
+        _ => return None,
+    };
+    let token = ctx.token.clone();
+    let item = match name {
+        Some(name) => name.syntax().parent(),
+        None => if token.kind() == SyntaxKind::WHITESPACE { token.prev_token()? } else { token }
+            .parent(),
+    }?;
+    complete_trait_impl(
+        acc,
+        ctx,
+        kind,
+        replacement_range(ctx, &item),
+        // item -> ASSOC_ITEM_LIST -> IMPL
+        ast::Impl::cast(item.parent()?.parent()?)?,
+    );
+    Some(())
 }
 
-fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, TextRange, ast::Impl)> {
-    match &ctx.ident_ctx {
-        IdentContext::Name(NameContext { name, kind, .. }) => {
-            let kind = match kind {
-                NameKind::Const => ImplCompletionKind::Const,
-                NameKind::Function => ImplCompletionKind::Fn,
-                NameKind::TypeAlias => ImplCompletionKind::TypeAlias,
-                _ => return None,
-            };
-            let token = ctx.token.clone();
-            let item = match name {
-                Some(name) => name.syntax().parent(),
-                None => {
-                    if token.kind() == SyntaxKind::WHITESPACE { token.prev_token()? } else { token }
-                        .parent()
-                }
-            }?;
-            Some((
-                kind,
-                replacement_range(ctx, &item),
-                // item -> ASSOC_ITEM_LIST -> IMPL
-                ast::Impl::cast(item.parent()?.parent()?)?,
-            ))
-        }
-        IdentContext::NameRef(NameRefContext {
+pub(crate) fn complete_trait_impl_name_ref(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name_ref_ctx: &NameRefContext,
+) -> Option<()> {
+    match name_ref_ctx {
+        NameRefContext {
             nameref,
             kind:
                 Some(NameRefKind::Path(
@@ -113,15 +101,44 @@ fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, Text
                         ..
                     },
                 )),
-        }) if path_ctx.is_trivial_path() => Some((
+        } if path_ctx.is_trivial_path() => complete_trait_impl(
+            acc,
+            ctx,
             ImplCompletionKind::All,
             match nameref {
                 Some(name) => name.syntax().text_range(),
                 None => ctx.source_range(),
             },
             ctx.impl_def.clone()?,
-        )),
-        _ => None,
+        ),
+        _ => (),
+    }
+    Some(())
+}
+
+fn complete_trait_impl(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    kind: ImplCompletionKind,
+    replacement_range: TextRange,
+    impl_def: ast::Impl,
+) {
+    if let Some(hir_impl) = ctx.sema.to_def(&impl_def) {
+        get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| {
+            use self::ImplCompletionKind::*;
+            match (item, kind) {
+                (hir::AssocItem::Function(func), All | Fn) => {
+                    add_function_impl(acc, ctx, replacement_range, func, hir_impl)
+                }
+                (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => {
+                    add_type_alias_impl(acc, ctx, replacement_range, type_alias)
+                }
+                (hir::AssocItem::Const(const_), All | Const) => {
+                    add_const_impl(acc, ctx, replacement_range, const_, hir_impl)
+                }
+                _ => {}
+            }
+        });
     }
 }
 
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 2e266b7714c..57d545ab8fe 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -1,23 +1,17 @@
-//! Completes keywords, except:
-//! - `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.
+//! Completes `where` and `for` keywords.
 
-use syntax::ast::Item;
+use syntax::ast::{self, Item};
 
-use crate::{
-    context::{NameRefContext, NameRefKind},
-    CompletionContext, Completions,
-};
-
-pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
-    let item = match ctx.nameref_ctx() {
-        Some(NameRefContext { kind: Some(NameRefKind::Keyword(item)), .. }) => item,
-        _ => return,
-    };
+use crate::{CompletionContext, Completions};
 
+pub(crate) fn complete_special_keywords(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    keyword_item: &ast::Item,
+) {
     let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
 
-    match item {
+    match keyword_item {
         Item::Impl(it) => {
             if it.for_token().is_none() && it.trait_().is_none() && it.self_ty().is_some() {
                 add_keyword("for", "for");
diff --git a/crates/ide-completion/src/completions/lifetime.rs b/crates/ide-completion/src/completions/lifetime.rs
index 12fcc8920a1..76e1c2e510a 100644
--- a/crates/ide-completion/src/completions/lifetime.rs
+++ b/crates/ide-completion/src/completions/lifetime.rs
@@ -16,13 +16,17 @@ use crate::{
 };
 
 /// Completes lifetimes.
-pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext) {
-    let (lp, lifetime) = match ctx.lifetime_ctx() {
-        Some(LifetimeContext { kind: LifetimeKind::Lifetime, lifetime }) => (None, lifetime),
-        Some(LifetimeContext {
+pub(crate) fn complete_lifetime(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    lifetime_ctx: &LifetimeContext,
+) {
+    let (lp, lifetime) = match lifetime_ctx {
+        LifetimeContext { kind: LifetimeKind::Lifetime, lifetime } => (None, lifetime),
+        LifetimeContext {
             kind: LifetimeKind::LifetimeParam { is_decl: false, param },
             lifetime,
-        }) => (Some(param), lifetime),
+        } => (Some(param), lifetime),
         _ => return,
     };
     let param_lifetime = match (lifetime, lp.and_then(|lp| lp.lifetime())) {
@@ -48,8 +52,12 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext)
 }
 
 /// Completes labels.
-pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) {
-    if !matches!(ctx.lifetime_ctx(), Some(LifetimeContext { kind: LifetimeKind::LabelRef, .. })) {
+pub(crate) fn complete_label(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    lifetime_ctx: &LifetimeContext,
+) {
+    if !matches!(lifetime_ctx, LifetimeContext { kind: LifetimeKind::LabelRef, .. }) {
         return;
     }
     ctx.process_all_names_raw(&mut |name, res| {
diff --git a/crates/ide-completion/src/completions/mod_.rs b/crates/ide-completion/src/completions/mod_.rs
index 3e03528f0cd..8dd1d1d8ac8 100644
--- a/crates/ide-completion/src/completions/mod_.rs
+++ b/crates/ide-completion/src/completions/mod_.rs
@@ -15,9 +15,13 @@ use crate::{
 };
 
 /// Complete mod declaration, i.e. `mod $0;`
-pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
-    let mod_under_caret = match ctx.name_ctx() {
-        Some(NameContext { kind: NameKind::Module(mod_under_caret), .. }) => mod_under_caret,
+pub(crate) fn complete_mod(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name_ctx: &NameContext,
+) -> Option<()> {
+    let mod_under_caret = match name_ctx {
+        NameContext { kind: NameKind::Module(mod_under_caret), .. } => mod_under_caret,
         _ => return None,
     };
     if mod_under_caret.item_list().is_some() {
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index b2630798bbc..1ecae1c4846 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -5,22 +5,16 @@ use ide_db::FxHashSet;
 use syntax::ast::Pat;
 
 use crate::{
-    context::{PathCompletionCtx, PatternRefutability, Qualified},
+    context::{PathCompletionCtx, PathKind, PatternContext, PatternRefutability, Qualified},
     CompletionContext, Completions,
 };
 
 /// Completes constants and paths in unqualified patterns.
-pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
-    let patctx = match &ctx.pattern_ctx {
-        Some(ctx) => ctx,
-        _ => return,
-    };
-
-    if let Some(path_ctx) = ctx.path_context() {
-        pattern_path_completion(acc, ctx, path_ctx);
-        return;
-    }
-
+pub(crate) fn complete_pattern(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    patctx: &PatternContext,
+) {
     match patctx.parent_pat.as_ref() {
         Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
         Some(Pat::RefPat(r)) => {
@@ -108,22 +102,20 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
     });
 }
 
-fn pattern_path_completion(
+pub(crate) fn pattern_path_completion(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    PathCompletionCtx { qualified, kind, .. }: &PathCompletionCtx,
 ) {
+    if !matches!(kind, PathKind::Pat) {
+        return;
+    }
     match qualified {
-        Qualified::With { resolution, is_super_chain, .. } => {
+        Qualified::With { resolution: Some(resolution), is_super_chain, .. } => {
             if *is_super_chain {
                 acc.add_keyword(ctx, "super::");
             }
 
-            let resolution = match resolution {
-                Some(it) => it,
-                None => return,
-            };
-
             match resolution {
                 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
                     let module_scope = module.scope(ctx.db, Some(ctx.module));
@@ -208,6 +200,6 @@ fn pattern_path_completion(
 
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer => {}
+        Qualified::Infer | Qualified::With { .. } => {}
     }
 }
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index 888b8f34884..5af44aa4b68 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -13,27 +13,22 @@ use text_edit::TextEdit;
 
 use crate::{
     completions::postfix::format_like::add_format_like_completions,
-    context::{CompletionContext, DotAccess, DotAccessKind, NameRefContext, NameRefKind},
+    context::{CompletionContext, DotAccess, DotAccessKind},
     item::{Builder, CompletionRelevancePostfixMatch},
     CompletionItem, CompletionItemKind, CompletionRelevance, Completions, SnippetScope,
 };
 
-pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
+pub(crate) fn complete_postfix(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    dot_access: &DotAccess,
+) {
     if !ctx.config.enable_postfix_completions {
         return;
     }
 
-    let (dot_receiver, receiver_ty, receiver_is_ambiguous_float_literal) = match ctx.nameref_ctx() {
-        Some(NameRefContext {
-            kind:
-                Some(NameRefKind::DotAccess(DotAccess {
-                    receiver_ty: Some(ty),
-                    receiver: Some(it),
-                    kind,
-                    ..
-                })),
-            ..
-        }) => (
+    let (dot_receiver, receiver_ty, receiver_is_ambiguous_float_literal) = match dot_access {
+        DotAccess { receiver_ty: Some(ty), receiver: Some(it), kind, .. } => (
             it,
             &ty.original,
             match *kind {
diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs
index 5ba355f6ae8..eaab4cb4eea 100644
--- a/crates/ide-completion/src/completions/record.rs
+++ b/crates/ide-completion/src/completions/record.rs
@@ -1,36 +1,34 @@
 //! Complete fields in record literals and patterns.
 use ide_db::SymbolKind;
-use syntax::{ast::Expr, T};
+use syntax::{
+    ast::{self, Expr},
+    T,
+};
 
 use crate::{
-    context::{
-        NameRefContext, NameRefKind, PathCompletionCtx, PathKind, PatternContext, Qualified,
-    },
+    context::{PathCompletionCtx, PathKind, PatternContext, Qualified},
     CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
     CompletionRelevancePostfixMatch, Completions,
 };
 
-pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
-    let missing_fields = if let Some(PatternContext { record_pat: Some(record_pat), .. }) =
-        &ctx.pattern_ctx
-    {
-        ctx.sema.record_pattern_missing_fields(record_pat)
-    } else if let Some(NameRefContext {
-        kind:
-            Some(
-                NameRefKind::RecordExpr(record_expr)
-                | NameRefKind::Path(PathCompletionCtx {
-                    kind: PathKind::Expr { is_func_update: Some(record_expr), .. },
-                    qualified: Qualified::No,
-                    ..
-                }),
-            ),
-        ..
-    }) = ctx.nameref_ctx()
-    {
-        let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
+pub(crate) fn complete_record_pattern_fields(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    pattern_ctx: &PatternContext,
+) {
+    if let PatternContext { record_pat: Some(record_pat), .. } = pattern_ctx {
+        complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat));
+    }
+}
+pub(crate) fn complete_record_expr_fields_record_expr(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    record_expr: &ast::RecordExpr,
+) {
+    let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
 
-        if let Some(hir::Adt::Union(un)) = ty.as_ref().and_then(|t| t.original.as_adt()) {
+    let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
+        Some(hir::Adt::Union(un)) => {
             // ctx.sema.record_literal_missing_fields will always return
             // an empty Vec on a union literal. This is normally
             // reasonable, but here we'd like to present the full list
@@ -40,47 +38,80 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
 
             match were_fields_specified {
                 false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
-                true => vec![],
+                true => return,
             }
-        } else {
+        }
+        _ => {
             let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
 
-            let default_trait = ctx.famous_defs().core_default_Default();
-            let impl_default_trait =
-                default_trait.zip(ty.as_ref()).map_or(false, |(default_trait, ty)| {
-                    ty.original.impls_trait(ctx.db, default_trait, &[])
-                });
-
-            if impl_default_trait && !missing_fields.is_empty() {
-                let completion_text = "..Default::default()";
-                let mut item =
-                    CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
-                let completion_text =
-                    completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
-                item.insert_text(completion_text).set_relevance(CompletionRelevance {
-                    postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
-                    ..Default::default()
-                });
-                item.add_to(acc);
-            }
+            add_default_update(acc, ctx, ty, &missing_fields);
             if ctx.previous_token_is(T![.]) {
                 let mut item =
                     CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), "..");
                 item.insert_text(".");
                 item.add_to(acc);
-                return None;
+                return;
             }
             missing_fields
         }
-    } else {
-        return None;
     };
+    complete_fields(acc, ctx, missing_fields);
+}
+
+fn add_default_update(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    ty: Option<hir::TypeInfo>,
+    missing_fields: &[(hir::Field, hir::Type)],
+) {
+    let default_trait = ctx.famous_defs().core_default_Default();
+    let impl_default_trait = default_trait
+        .zip(ty.as_ref())
+        .map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
+    if impl_default_trait && !missing_fields.is_empty() {
+        let completion_text = "..Default::default()";
+        let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
+        let completion_text =
+            completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
+        item.insert_text(completion_text).set_relevance(CompletionRelevance {
+            postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
+            ..Default::default()
+        });
+        item.add_to(acc);
+    }
+}
+
+pub(crate) fn complete_record_expr_func_update(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+) {
+    if let PathCompletionCtx {
+        kind: PathKind::Expr { is_func_update: Some(record_expr), .. },
+        qualified: Qualified::No,
+        ..
+    } = path_ctx
+    {
+        let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
 
+        match ty.as_ref().and_then(|t| t.original.as_adt()) {
+            Some(hir::Adt::Union(_)) => (),
+            _ => {
+                let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
+                add_default_update(acc, ctx, ty, &missing_fields);
+            }
+        };
+    }
+}
+
+fn complete_fields(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    missing_fields: Vec<(hir::Field, hir::Type)>,
+) {
     for (field, ty) in missing_fields {
         acc.add_field(ctx, None, field, &ty);
     }
-
-    Some(())
 }
 
 #[cfg(test)]
diff --git a/crates/ide-completion/src/completions/snippet.rs b/crates/ide-completion/src/completions/snippet.rs
index 293311fe910..48366987f40 100644
--- a/crates/ide-completion/src/completions/snippet.rs
+++ b/crates/ide-completion/src/completions/snippet.rs
@@ -15,13 +15,17 @@ fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str)
     item
 }
 
-pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) {
-    let &can_be_stmt = match ctx.path_context() {
-        Some(PathCompletionCtx {
+pub(crate) fn complete_expr_snippet(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+) {
+    let &can_be_stmt = match path_ctx {
+        PathCompletionCtx {
             qualified: Qualified::No,
             kind: PathKind::Expr { in_block_expr, .. },
             ..
-        }) => in_block_expr,
+        } => in_block_expr,
         _ => return,
     };
 
@@ -40,13 +44,17 @@ pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte
     }
 }
 
-pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) {
-    let path_kind = match ctx.path_context() {
-        Some(PathCompletionCtx {
+pub(crate) fn complete_item_snippet(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+) {
+    let path_kind = match path_ctx {
+        PathCompletionCtx {
             qualified: Qualified::No,
             kind: kind @ (PathKind::Item { .. } | PathKind::Expr { in_block_expr: true, .. }),
             ..
-        }) => kind,
+        } => kind,
         _ => return,
     };
     if !ctx.qualifier_ctx.none() {
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index b6666ef1a4a..b8d172696d7 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -10,11 +10,15 @@ use crate::{
     CompletionContext, Completions,
 };
 
-pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext) {
+pub(crate) fn complete_type_path(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+) {
     let _p = profile::span("complete_type_path");
 
-    let (location, qualified) = match ctx.path_context() {
-        Some(PathCompletionCtx { kind: PathKind::Type { location }, qualified, .. }) => {
+    let (location, qualified) = match path_ctx {
+        PathCompletionCtx { kind: PathKind::Type { location }, qualified, .. } => {
             (location, qualified)
         }
         _ => return,
@@ -58,11 +62,8 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
             .into_iter()
             .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, item)),
-        Qualified::With { resolution, .. } => {
-            let resolution = match resolution {
-                Some(it) => it,
-                None => return,
-            };
+        Qualified::With { resolution: None, .. } => {}
+        Qualified::With { resolution: Some(resolution), .. } => {
             // Add associated types on type parameters and `Self`.
             ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
                 acc.add_type_alias(ctx, alias);
@@ -87,7 +88,7 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
                         hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
                         hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
                         hir::ModuleDef::BuiltinType(builtin) => builtin.ty(ctx.db),
-                        _ => unreachable!(),
+                        _ => return,
                     };
 
                     // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
@@ -190,14 +191,16 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
     }
 }
 
-pub(crate) fn complete_inferred_type(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
-    let pat = match ctx.path_context() {
-        Some(
-            ctx @ PathCompletionCtx {
-                kind: PathKind::Type { location: TypeLocation::TypeAscription(ascription), .. },
-                ..
-            },
-        ) if ctx.is_trivial_path() => ascription,
+pub(crate) fn complete_inferred_type(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+) -> Option<()> {
+    let pat = match path_ctx {
+        PathCompletionCtx {
+            kind: PathKind::Type { location: TypeLocation::TypeAscription(ascription), .. },
+            ..
+        } if path_ctx.is_trivial_path() => ascription,
         _ => return None,
     };
     let x = match pat {
diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs
index 64fa4263959..9ffcee400d9 100644
--- a/crates/ide-completion/src/completions/use_.rs
+++ b/crates/ide-completion/src/completions/use_.rs
@@ -12,9 +12,13 @@ use crate::{
     CompletionItem, CompletionItemKind, CompletionRelevance, Completions,
 };
 
-pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext) {
-    let (qualified, name_ref, use_tree_parent) = match ctx.nameref_ctx() {
-        Some(NameRefContext {
+pub(crate) fn complete_use_tree(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name_ref_ctx: &NameRefContext,
+) {
+    let (qualified, name_ref, use_tree_parent) = match name_ref_ctx {
+        NameRefContext {
             kind:
                 Some(NameRefKind::Path(PathCompletionCtx {
                     kind: PathKind::Use,
@@ -24,12 +28,12 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
                 })),
             nameref,
             ..
-        }) => (qualified, nameref, use_tree_parent),
+        } => (qualified, nameref, use_tree_parent),
         _ => return,
     };
 
     match qualified {
-        Qualified::With { path, resolution, is_super_chain } => {
+        Qualified::With { path, resolution: Some(resolution), is_super_chain } => {
             if *is_super_chain {
                 acc.add_keyword(ctx, "super::");
             }
@@ -43,11 +47,6 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
                 acc.add_keyword(ctx, "self");
             }
 
-            let resolution = match resolution {
-                Some(it) => it,
-                None => return,
-            };
-
             let mut already_imported_names = FxHashSet::default();
             if let Some(list) = ctx.token.parent_ancestors().find_map(ast::UseTreeList::cast) {
                 let use_tree = list.parent_use_tree();
@@ -135,6 +134,6 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer => {}
+        Qualified::Infer | Qualified::With { resolution: None, .. } => {}
     }
 }
diff --git a/crates/ide-completion/src/completions/vis.rs b/crates/ide-completion/src/completions/vis.rs
index 319976737e8..18513039e67 100644
--- a/crates/ide-completion/src/completions/vis.rs
+++ b/crates/ide-completion/src/completions/vis.rs
@@ -7,29 +7,31 @@ use crate::{
     Completions,
 };
 
-pub(crate) fn complete_vis_path(acc: &mut Completions, ctx: &CompletionContext) {
-    let (qualified, &has_in_token) = match ctx.path_context() {
-        Some(PathCompletionCtx { kind: PathKind::Vis { has_in_token }, qualified, .. }) => {
+pub(crate) fn complete_vis_path(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx: &PathCompletionCtx,
+) {
+    let (qualified, &has_in_token) = match path_ctx {
+        PathCompletionCtx { kind: PathKind::Vis { has_in_token }, qualified, .. } => {
             (qualified, has_in_token)
         }
         _ => return,
     };
 
     match qualified {
-        Qualified::With { resolution, is_super_chain, .. } => {
+        Qualified::With {
+            resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
+            is_super_chain,
+            ..
+        } => {
             // Try completing next child module of the path that is still a parent of the current module
-            if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) = resolution {
-                let next_towards_current = ctx
-                    .module
-                    .path_to_root(ctx.db)
-                    .into_iter()
-                    .take_while(|it| it != module)
-                    .last();
-                if let Some(next) = next_towards_current {
-                    if let Some(name) = next.name(ctx.db) {
-                        cov_mark::hit!(visibility_qualified);
-                        acc.add_resolution(ctx, name, ScopeDef::ModuleDef(next.into()));
-                    }
+            let next_towards_current =
+                ctx.module.path_to_root(ctx.db).into_iter().take_while(|it| it != module).last();
+            if let Some(next) = next_towards_current {
+                if let Some(name) = next.name(ctx.db) {
+                    cov_mark::hit!(visibility_qualified);
+                    acc.add_resolution(ctx, name, ScopeDef::ModuleDef(next.into()));
                 }
             }
 
@@ -37,7 +39,7 @@ pub(crate) fn complete_vis_path(acc: &mut Completions, ctx: &CompletionContext)
                 acc.add_keyword(ctx, "super::");
             }
         }
-        Qualified::Absolute | Qualified::Infer => {}
+        Qualified::Absolute | Qualified::Infer | Qualified::With { .. } => {}
         Qualified::No => {
             if !has_in_token {
                 cov_mark::hit!(kw_completion_in);
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 6af24f87489..825047c5cf9 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -362,6 +362,7 @@ impl<'a> CompletionContext<'a> {
         FamousDefs(&self.sema, self.krate)
     }
 
+    // FIXME: This shouldn't exist
     pub(super) fn nameref_ctx(&self) -> Option<&NameRefContext> {
         match &self.ident_ctx {
             IdentContext::NameRef(it) => Some(it),
@@ -369,20 +370,7 @@ impl<'a> CompletionContext<'a> {
         }
     }
 
-    pub(super) fn name_ctx(&self) -> Option<&NameContext> {
-        match &self.ident_ctx {
-            IdentContext::Name(it) => Some(it),
-            _ => None,
-        }
-    }
-
-    pub(super) fn lifetime_ctx(&self) -> Option<&LifetimeContext> {
-        match &self.ident_ctx {
-            IdentContext::Lifetime(it) => Some(it),
-            _ => None,
-        }
-    }
-
+    // FIXME: This shouldn't exist
     pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> {
         match self.nameref_ctx() {
             Some(NameRefContext {
@@ -393,10 +381,7 @@ impl<'a> CompletionContext<'a> {
         }
     }
 
-    pub(crate) fn has_dot_receiver(&self) -> bool {
-        self.dot_receiver().is_some()
-    }
-
+    // FIXME: This shouldn't exist
     pub(crate) fn path_context(&self) -> Option<&PathCompletionCtx> {
         self.nameref_ctx().and_then(|ctx| match &ctx.kind {
             Some(NameRefKind::Path(path)) => Some(path),
@@ -404,6 +389,7 @@ impl<'a> CompletionContext<'a> {
         })
     }
 
+    // FIXME: This shouldn't exist
     pub(crate) fn path_qual(&self) -> Option<&ast::Path> {
         self.path_context().and_then(|it| match &it.qualified {
             Qualified::With { path, .. } => Some(path),
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index f53c5f6747a..e0e4926463c 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -23,7 +23,14 @@ use ide_db::{
 use syntax::algo;
 use text_edit::TextEdit;
 
-use crate::{completions::Completions, context::CompletionContext};
+use crate::{
+    completions::Completions,
+    context::{
+        CompletionContext,
+        IdentContext::{self, NameRef},
+        NameRefContext, NameRefKind,
+    },
+};
 
 pub use crate::{
     config::{CallableSnippets, CompletionConfig},
@@ -145,40 +152,94 @@ pub fn completions(
     trigger_character: Option<char>,
 ) -> Option<Completions> {
     let ctx = &CompletionContext::new(db, position, config)?;
-    let mut acc = Completions::default();
+    let mut completions = Completions::default();
 
-    {
-        let acc = &mut acc;
+    // prevent `(` from triggering unwanted completion noise
+    if trigger_character == Some('(') {
+        if let NameRef(NameRefContext { kind: Some(NameRefKind::Path(path_ctx)), .. }) =
+            &ctx.ident_ctx
+        {
+            completions::vis::complete_vis_path(&mut completions, ctx, path_ctx);
+        }
         // prevent `(` from triggering unwanted completion noise
-        if trigger_character != Some('(') {
-            completions::attribute::complete_attribute(acc, ctx);
-            completions::attribute::complete_derive(acc, ctx);
-            completions::attribute::complete_known_attribute_input(acc, ctx);
-            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);
-            completions::item_list::complete_item_list(acc, ctx);
-            completions::keyword::complete_expr_keyword(acc, ctx);
-            completions::lifetime::complete_label(acc, ctx);
-            completions::lifetime::complete_lifetime(acc, ctx);
-            completions::mod_::complete_mod(acc, ctx);
-            completions::pattern::complete_pattern(acc, ctx);
-            completions::postfix::complete_postfix(acc, ctx);
-            completions::record::complete_record(acc, ctx);
-            completions::snippet::complete_expr_snippet(acc, ctx);
-            completions::snippet::complete_item_snippet(acc, ctx);
-            completions::r#type::complete_type_path(acc, ctx);
-            completions::r#type::complete_inferred_type(acc, ctx);
-            completions::use_::complete_use_tree(acc, ctx);
+        return Some(completions);
+    }
+
+    {
+        let acc = &mut completions;
+
+        match &ctx.ident_ctx {
+            IdentContext::Name(name_ctx) => {
+                completions::field::complete_field_list_record_variant(acc, ctx, name_ctx);
+                completions::mod_::complete_mod(acc, ctx, name_ctx);
+                completions::item_list::trait_impl::complete_trait_impl_name(acc, ctx, name_ctx);
+            }
+            NameRef(name_ref_ctx @ NameRefContext { kind, .. }) => {
+                completions::expr::complete_expr_path(acc, ctx, name_ref_ctx);
+                completions::field::complete_field_list_tuple_variant(acc, ctx, name_ref_ctx);
+                completions::use_::complete_use_tree(acc, ctx, name_ref_ctx);
+                completions::item_list::complete_item_list(acc, ctx, name_ref_ctx);
+                match kind {
+                    Some(NameRefKind::Path(path_ctx)) => {
+                        completions::record::complete_record_expr_func_update(acc, ctx, path_ctx);
+                        completions::attribute::complete_attribute(acc, ctx, path_ctx);
+                        completions::attribute::complete_derive(acc, ctx, path_ctx);
+                        completions::dot::complete_undotted_self(acc, ctx, path_ctx);
+                        completions::pattern::pattern_path_completion(acc, ctx, path_ctx);
+                        completions::r#type::complete_inferred_type(acc, ctx, path_ctx);
+                        completions::r#type::complete_type_path(acc, ctx, path_ctx);
+                        completions::snippet::complete_expr_snippet(acc, ctx, path_ctx);
+                        completions::snippet::complete_item_snippet(acc, ctx, path_ctx);
+                        completions::vis::complete_vis_path(acc, ctx, path_ctx);
+                    }
+                    Some(NameRefKind::DotAccess(dot_access)) => {
+                        completions::dot::complete_dot(acc, ctx, dot_access);
+                        completions::postfix::complete_postfix(acc, ctx, dot_access);
+                    }
+                    Some(NameRefKind::Keyword(item)) => {
+                        completions::keyword::complete_special_keywords(acc, ctx, item);
+                    }
+                    Some(NameRefKind::RecordExpr(record_expr)) => {
+                        completions::record::complete_record_expr_fields_record_expr(
+                            acc,
+                            ctx,
+                            record_expr,
+                        );
+                    }
+                    None => (),
+                }
+            }
+            IdentContext::Lifetime(lifetime_ctx) => {
+                completions::lifetime::complete_label(acc, ctx, lifetime_ctx);
+                completions::lifetime::complete_lifetime(acc, ctx, lifetime_ctx);
+            }
+            IdentContext::String { original, expanded: Some(expanded) } => {
+                completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
+                completions::format_string::format_string(acc, ctx, original, expanded);
+            }
+            IdentContext::UnexpandedAttrTT { fake_attribute_under_caret: Some(attr) } => {
+                completions::attribute::complete_known_attribute_input(acc, ctx, attr);
+            }
+            IdentContext::UnexpandedAttrTT { .. } | IdentContext::String { .. } => (),
         }
-        completions::vis::complete_vis_path(acc, ctx);
+
+        if let Some(pattern_ctx) = &ctx.pattern_ctx {
+            completions::fn_param::complete_fn_param(acc, ctx, pattern_ctx);
+            completions::record::complete_record_pattern_fields(acc, ctx, pattern_ctx);
+            // FIXME: this check is odd, we shouldn't need this?
+            if !matches!(
+                ctx.ident_ctx,
+                IdentContext::NameRef(NameRefContext { kind: Some(NameRefKind::Path(_)), .. })
+            ) {
+                completions::pattern::complete_pattern(acc, ctx, pattern_ctx);
+            }
+        }
+
+        // FIXME: This should be split
+        completions::flyimport::import_on_the_fly(acc, ctx);
     }
 
-    Some(acc)
+    Some(completions)
 }
 
 /// Resolves additional completion data at the position given.
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index 942dc033687..68908e330a4 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -17,7 +17,7 @@ use ide_db::{
 use syntax::{SmolStr, SyntaxKind, TextRange};
 
 use crate::{
-    context::{PathCompletionCtx, PathKind},
+    context::{IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind},
     item::{Builder, CompletionRelevanceTypeMatch},
     render::{function::render_fn, literal::render_variant_lit, macro_::render_macro},
     CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
@@ -75,7 +75,13 @@ impl<'a> RenderContext<'a> {
     }
 
     pub(crate) fn path_is_call(&self) -> bool {
-        self.completion.path_context().map_or(false, |it| it.has_call_parens)
+        matches!(
+            self.completion.ident_ctx,
+            IdentContext::NameRef(NameRefContext {
+                kind: Some(NameRefKind::Path(PathCompletionCtx { has_call_parens: true, .. })),
+                ..
+            })
+        )
     }
 
     fn is_deprecated(&self, def: impl HasAttrs) -> bool {
@@ -285,8 +291,15 @@ 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, .. })
+        ctx.completion.ident_ctx,
+        IdentContext::NameRef(NameRefContext {
+            kind: Some(NameRefKind::Path(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() {
@@ -937,7 +950,6 @@ fn main() -> RawIdentTable {
 
     #[test]
     fn no_parens_in_use_item() {
-        cov_mark::check!(no_parens_in_use_item);
         check_edit(
             "foo",
             r#"
diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs
index 566eaa575d4..ad240503c14 100644
--- a/crates/ide-completion/src/render/function.rs
+++ b/crates/ide-completion/src/render/function.rs
@@ -8,7 +8,7 @@ use syntax::SmolStr;
 
 use crate::{
     context::{
-        CompletionContext, DotAccess, DotAccessKind, NameRefContext, NameRefKind,
+        CompletionContext, DotAccess, DotAccessKind, IdentContext, NameRefContext, NameRefKind,
         PathCompletionCtx, PathKind,
     },
     item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
@@ -91,9 +91,10 @@ fn render(
         .lookup_by(name.to_smol_str());
 
     match completion.config.snippet_cap {
-        Some(cap) if should_add_parens(completion) => {
-            let (self_param, params) = params(completion, func, &func_kind);
-            add_call_parens(&mut item, completion, cap, call, self_param, params);
+        Some(cap) => {
+            if let Some((self_param, params)) = params(completion, func, &func_kind) {
+                add_call_parens(&mut item, completion, cap, call, self_param, params);
+            }
         }
         _ => (),
     }
@@ -194,48 +195,6 @@ fn ref_of_param(ctx: &CompletionContext, arg: &str, ty: &hir::Type) -> &'static
     ""
 }
 
-fn should_add_parens(ctx: &CompletionContext) -> bool {
-    if ctx.config.callable.is_none() {
-        return false;
-    }
-
-    match ctx.path_context() {
-        Some(PathCompletionCtx { kind: PathKind::Expr { .. }, has_call_parens: true, .. }) => {
-            return false
-        }
-        Some(PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. }) => {
-            cov_mark::hit!(no_parens_in_use_item);
-            return false;
-        }
-        _ => {}
-    };
-
-    if matches!(
-        ctx.nameref_ctx(),
-        Some(NameRefContext {
-            kind: Some(NameRefKind::DotAccess(DotAccess {
-                kind: DotAccessKind::Method { has_parens: true },
-                ..
-            })),
-            ..
-        })
-    ) {
-        return false;
-    }
-
-    // Don't add parentheses if the expected type is some function reference.
-    if let Some(ty) = &ctx.expected_type {
-        // FIXME: check signature matches?
-        if ty.is_fn() {
-            cov_mark::hit!(no_call_parens_if_fn_ptr_needed);
-            return false;
-        }
-    }
-
-    // Nothing prevents us from adding parentheses
-    true
-}
-
 fn detail(db: &dyn HirDatabase, func: hir::Function) -> String {
     let mut ret_ty = func.ret_type(db);
     let mut detail = String::new();
@@ -285,13 +244,52 @@ fn params(
     ctx: &CompletionContext<'_>,
     func: hir::Function,
     func_kind: &FuncKind,
-) -> (Option<hir::SelfParam>, Vec<hir::Param>) {
-    let self_param = if ctx.has_dot_receiver() || matches!(func_kind, FuncKind::Method(Some(_))) {
+) -> Option<(Option<hir::SelfParam>, Vec<hir::Param>)> {
+    if ctx.config.callable.is_none() {
+        return None;
+    }
+
+    let has_dot_receiver = match ctx.ident_ctx {
+        IdentContext::NameRef(NameRefContext {
+            kind:
+                Some(NameRefKind::DotAccess(DotAccess {
+                    kind: DotAccessKind::Method { has_parens: true },
+                    ..
+                })),
+            ..
+        }) => return None,
+        IdentContext::NameRef(NameRefContext {
+            kind: Some(NameRefKind::DotAccess(DotAccess { .. })),
+            ..
+        }) => true,
+        IdentContext::NameRef(NameRefContext {
+            kind:
+                Some(NameRefKind::Path(
+                    PathCompletionCtx {
+                        kind: PathKind::Expr { .. }, has_call_parens: true, ..
+                    }
+                    | PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. },
+                )),
+            ..
+        }) => return None,
+        _ => false,
+    };
+
+    // Don't add parentheses if the expected type is some function reference.
+    if let Some(ty) = &ctx.expected_type {
+        // FIXME: check signature matches?
+        if ty.is_fn() {
+            cov_mark::hit!(no_call_parens_if_fn_ptr_needed);
+            return None;
+        }
+    }
+
+    let self_param = if has_dot_receiver || matches!(func_kind, FuncKind::Method(Some(_))) {
         None
     } else {
         func.self_param(ctx.db)
     };
-    (self_param, func.params_without_self(ctx.db))
+    Some((self_param, func.params_without_self(ctx.db)))
 }
 
 #[cfg(test)]
diff --git a/crates/ide-completion/src/render/literal.rs b/crates/ide-completion/src/render/literal.rs
index fd76dedad06..1e03d066d14 100644
--- a/crates/ide-completion/src/render/literal.rs
+++ b/crates/ide-completion/src/render/literal.rs
@@ -4,7 +4,9 @@ use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind};
 use ide_db::SymbolKind;
 
 use crate::{
-    context::{CompletionContext, PathCompletionCtx, PathKind},
+    context::{
+        CompletionContext, IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind,
+    },
     item::{Builder, CompletionItem},
     render::{
         compute_ref_match, compute_type_match,
@@ -51,12 +53,19 @@ fn render(
 ) -> Option<Builder> {
     let db = completion.db;
     let mut kind = thing.kind(db);
-    let should_add_parens = match completion.path_context() {
-        Some(PathCompletionCtx { has_call_parens: true, .. }) => false,
-        Some(PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. }) => {
-            cov_mark::hit!(no_parens_in_use_item);
-            false
-        }
+    let should_add_parens = match &completion.ident_ctx {
+        IdentContext::NameRef(NameRefContext {
+            kind: Some(NameRefKind::Path(PathCompletionCtx { has_call_parens: true, .. })),
+            ..
+        }) => false,
+        IdentContext::NameRef(NameRefContext {
+            kind:
+                Some(NameRefKind::Path(PathCompletionCtx {
+                    kind: PathKind::Use | PathKind::Type { .. },
+                    ..
+                })),
+            ..
+        }) => false,
         _ => true,
     };
 
diff --git a/crates/ide-completion/src/render/macro_.rs b/crates/ide-completion/src/render/macro_.rs
index de527860d8c..26690d22abe 100644
--- a/crates/ide-completion/src/render/macro_.rs
+++ b/crates/ide-completion/src/render/macro_.rs
@@ -5,7 +5,7 @@ use ide_db::SymbolKind;
 use syntax::SmolStr;
 
 use crate::{
-    context::{PathCompletionCtx, PathKind},
+    context::{IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind},
     item::{Builder, CompletionItem},
     render::RenderContext,
 };
@@ -33,10 +33,11 @@ fn render(
     let is_fn_like = macro_.is_fn_like(completion.db);
     let (bra, ket) = if is_fn_like { guess_macro_braces(&name, docs_str) } else { ("", "") };
 
-    let needs_bang = match completion.path_context() {
-        Some(PathCompletionCtx { kind, has_macro_bang, .. }) => {
-            is_fn_like && *kind != PathKind::Use && !has_macro_bang
-        }
+    let needs_bang = match &completion.ident_ctx {
+        IdentContext::NameRef(NameRefContext {
+            kind: Some(NameRefKind::Path(PathCompletionCtx { kind, has_macro_bang, .. })),
+            ..
+        }) => is_fn_like && *kind != PathKind::Use && !has_macro_bang,
         _ => is_fn_like,
     };
 
diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs
index 5b403ae8ccc..33f169c1b9b 100644
--- a/crates/ide-completion/src/render/pattern.rs
+++ b/crates/ide-completion/src/render/pattern.rs
@@ -6,7 +6,9 @@ use itertools::Itertools;
 use syntax::SmolStr;
 
 use crate::{
-    context::{ParamKind, PathCompletionCtx, PatternContext},
+    context::{
+        IdentContext, NameRefContext, NameRefKind, ParamKind, PathCompletionCtx, PatternContext,
+    },
     render::{variant::visible_fields, RenderContext},
     CompletionItem, CompletionItemKind,
 };
@@ -78,8 +80,11 @@ fn render_pat(
     fields_omitted: bool,
 ) -> Option<String> {
     let has_call_parens = matches!(
-        ctx.completion.path_context(),
-        Some(PathCompletionCtx { has_call_parens: true, .. })
+        ctx.completion.ident_ctx,
+        IdentContext::NameRef(NameRefContext {
+            kind: Some(NameRefKind::Path(PathCompletionCtx { has_call_parens: true, .. })),
+            ..
+        })
     );
     let mut pat = match kind {
         StructKind::Tuple if !has_call_parens => {
diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs
index c7514e1b578..d9b31832085 100644
--- a/crates/ide-completion/src/tests/record.rs
+++ b/crates/ide-completion/src/tests/record.rs
@@ -160,8 +160,6 @@ fn main() {
 "#,
         expect![[r#"
             fd ..Default::default()
-            fd foo1                 u32
-            fd foo2                 u32
             fn main()               fn()
             lc foo                  Foo
             lc thing                i32
diff --git a/crates/ide-completion/src/tests/use_tree.rs b/crates/ide-completion/src/tests/use_tree.rs
index c169a62077c..3134915bdab 100644
--- a/crates/ide-completion/src/tests/use_tree.rs
+++ b/crates/ide-completion/src/tests/use_tree.rs
@@ -179,7 +179,6 @@ impl Foo {
 
 #[test]
 fn enum_no_parens_in_qualified_use_tree() {
-    cov_mark::check!(no_parens_in_use_item);
     cov_mark::check!(enum_plain_qualified_use_tree);
     check(
         r#"