about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-06-20 12:50:59 +0000
committerbors <bors@rust-lang.org>2022-06-20 12:50:59 +0000
commita2e7e4e42cc89efd05df3c04493a4dd396cebc46 (patch)
treec0bd57c2d2accb28c98b6800201f9badbf0d3b3b
parent427061da19723f2206fe4dcb175c9c43b9a6193d (diff)
parent90483321ee0b47d48a5019bd9bbb11b45a24ac84 (diff)
downloadrust-a2e7e4e42cc89efd05df3c04493a4dd396cebc46.tar.gz
rust-a2e7e4e42cc89efd05df3c04493a4dd396cebc46.zip
Auto merge of #12588 - Veykril:completions, r=Veykril
internal: More completion reorganizing
-rw-r--r--crates/ide-completion/src/completions.rs153
-rw-r--r--crates/ide-completion/src/completions/attribute.rs37
-rw-r--r--crates/ide-completion/src/completions/attribute/derive.rs37
-rw-r--r--crates/ide-completion/src/completions/dot.rs22
-rw-r--r--crates/ide-completion/src/completions/expr.rs65
-rw-r--r--crates/ide-completion/src/completions/field.rs34
-rw-r--r--crates/ide-completion/src/completions/item_list.rs57
-rw-r--r--crates/ide-completion/src/completions/item_list/trait_impl.rs72
-rw-r--r--crates/ide-completion/src/completions/keyword.rs4
-rw-r--r--crates/ide-completion/src/completions/mod_.rs11
-rw-r--r--crates/ide-completion/src/completions/pattern.rs9
-rw-r--r--crates/ide-completion/src/completions/record.rs15
-rw-r--r--crates/ide-completion/src/completions/snippet.rs55
-rw-r--r--crates/ide-completion/src/completions/type.rs27
-rw-r--r--crates/ide-completion/src/completions/use_.rs28
-rw-r--r--crates/ide-completion/src/completions/vis.rs16
-rw-r--r--crates/ide-completion/src/context.rs40
-rw-r--r--crates/ide-completion/src/context/analysis.rs38
-rw-r--r--crates/ide-completion/src/lib.rs74
-rw-r--r--crates/ide-completion/src/snippet.rs6
20 files changed, 411 insertions, 389 deletions
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 284372f7fc5..c1081dbde32 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -22,12 +22,15 @@ pub(crate) mod vis;
 
 use std::iter;
 
-use hir::{db::HirDatabase, known, ScopeDef};
+use hir::{known, ScopeDef};
 use ide_db::SymbolKind;
 use syntax::ast;
 
 use crate::{
-    context::Visible,
+    context::{
+        ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind, PathKind, PatternContext,
+        TypeLocation, Visible,
+    },
     item::Builder,
     render::{
         const_::render_const,
@@ -43,22 +46,6 @@ use crate::{
     CompletionContext, CompletionItem, CompletionItemKind,
 };
 
-fn module_or_attr(db: &dyn HirDatabase, def: ScopeDef) -> Option<ScopeDef> {
-    match def {
-        ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(db) => Some(def),
-        ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => Some(def),
-        _ => None,
-    }
-}
-
-fn module_or_fn_macro(db: &dyn HirDatabase, def: ScopeDef) -> Option<ScopeDef> {
-    match def {
-        ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(db) => Some(def),
-        ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => Some(def),
-        _ => None,
-    }
-}
-
 /// Represents an in-progress set of completions being built.
 #[derive(Debug, Default)]
 pub struct Completions {
@@ -181,6 +168,15 @@ impl Completions {
         self.add(render_resolution_simple(RenderContext::new(ctx), local_name, resolution).build());
     }
 
+    pub(crate) fn add_module(
+        &mut self,
+        ctx: &CompletionContext,
+        module: hir::Module,
+        local_name: hir::Name,
+    ) {
+        self.add_resolution(ctx, local_name, hir::ScopeDef::ModuleDef(module.into()));
+    }
+
     pub(crate) fn add_macro(
         &mut self,
         ctx: &CompletionContext,
@@ -437,3 +433,124 @@ fn enum_variants_with_paths(
         }
     }
 }
+
+pub(super) fn complete_name(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    NameContext { name, kind }: &NameContext,
+) {
+    match kind {
+        NameKind::Const => {
+            item_list::trait_impl::complete_trait_impl_const(acc, ctx, name);
+        }
+        NameKind::Function => {
+            item_list::trait_impl::complete_trait_impl_fn(acc, ctx, name);
+        }
+        NameKind::IdentPat(pattern_ctx) => complete_patterns(acc, ctx, pattern_ctx),
+        NameKind::Module(mod_under_caret) => {
+            mod_::complete_mod(acc, ctx, mod_under_caret);
+        }
+        NameKind::TypeAlias => {
+            item_list::trait_impl::complete_trait_impl_type_alias(acc, ctx, name);
+        }
+        NameKind::RecordField => {
+            field::complete_field_list_record_variant(acc, ctx);
+        }
+        NameKind::ConstParam
+        | NameKind::Enum
+        | NameKind::MacroDef
+        | NameKind::MacroRules
+        | NameKind::Rename
+        | NameKind::SelfParam
+        | NameKind::Static
+        | NameKind::Struct
+        | NameKind::Trait
+        | NameKind::TypeParam
+        | NameKind::Union
+        | NameKind::Variant => (),
+    }
+}
+
+pub(super) fn complete_name_ref(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    NameRefContext { nameref, kind }: &NameRefContext,
+) {
+    match kind {
+        NameRefKind::Path(path_ctx) => {
+            flyimport::import_on_the_fly_path(acc, ctx, path_ctx);
+
+            match &path_ctx.kind {
+                PathKind::Expr { expr_ctx } => {
+                    expr::complete_expr_path(acc, ctx, path_ctx, expr_ctx);
+
+                    dot::complete_undotted_self(acc, ctx, path_ctx, expr_ctx);
+                    item_list::complete_item_list_in_expr(acc, ctx, path_ctx, expr_ctx);
+                    record::complete_record_expr_func_update(acc, ctx, path_ctx, expr_ctx);
+                    snippet::complete_expr_snippet(acc, ctx, path_ctx, expr_ctx);
+                }
+                PathKind::Type { location } => {
+                    r#type::complete_type_path(acc, ctx, path_ctx, location);
+
+                    match location {
+                        TypeLocation::TupleField => {
+                            field::complete_field_list_tuple_variant(acc, ctx, path_ctx);
+                        }
+                        TypeLocation::TypeAscription(ascription) => {
+                            r#type::complete_ascribed_type(acc, ctx, path_ctx, ascription);
+                        }
+                        TypeLocation::GenericArgList(_)
+                        | TypeLocation::TypeBound
+                        | TypeLocation::ImplTarget
+                        | TypeLocation::ImplTrait
+                        | TypeLocation::Other => (),
+                    }
+                }
+                PathKind::Attr { attr_ctx } => {
+                    attribute::complete_attribute_path(acc, ctx, path_ctx, attr_ctx);
+                }
+                PathKind::Derive { existing_derives } => {
+                    attribute::complete_derive_path(acc, ctx, path_ctx, existing_derives);
+                }
+                PathKind::Item { kind } => {
+                    item_list::complete_item_list(acc, ctx, path_ctx, kind);
+
+                    snippet::complete_item_snippet(acc, ctx, path_ctx, kind);
+                    if let ItemListKind::TraitImpl(impl_) = kind {
+                        item_list::trait_impl::complete_trait_impl_item_by_name(
+                            acc, ctx, path_ctx, nameref, impl_,
+                        );
+                    }
+                }
+                PathKind::Pat { .. } => {
+                    pattern::complete_pattern_path(acc, ctx, path_ctx);
+                }
+                PathKind::Vis { has_in_token } => {
+                    vis::complete_vis_path(acc, ctx, path_ctx, has_in_token);
+                }
+                PathKind::Use => {
+                    use_::complete_use_path(acc, ctx, path_ctx, nameref);
+                }
+            }
+        }
+        NameRefKind::DotAccess(dot_access) => {
+            flyimport::import_on_the_fly_dot(acc, ctx, dot_access);
+            dot::complete_dot(acc, ctx, dot_access);
+            postfix::complete_postfix(acc, ctx, dot_access);
+        }
+        NameRefKind::Keyword(item) => {
+            keyword::complete_for_and_where(acc, ctx, item);
+        }
+        NameRefKind::RecordExpr(record_expr) => {
+            record::complete_record_expr_fields(acc, ctx, record_expr);
+        }
+        NameRefKind::Pattern(pattern_ctx) => complete_patterns(acc, ctx, pattern_ctx),
+    }
+}
+
+fn complete_patterns(acc: &mut Completions, ctx: &CompletionContext, pattern_ctx: &PatternContext) {
+    flyimport::import_on_the_fly_pat(acc, ctx, pattern_ctx);
+    fn_param::complete_fn_param(acc, ctx, pattern_ctx);
+    pattern::complete_pattern(acc, ctx, pattern_ctx);
+    record::complete_record_pattern_fields(acc, ctx, pattern_ctx);
+}
diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs
index 992d7eabd8a..37e042a1609 100644
--- a/crates/ide-completion/src/completions/attribute.rs
+++ b/crates/ide-completion/src/completions/attribute.rs
@@ -17,8 +17,7 @@ use syntax::{
 };
 
 use crate::{
-    completions::module_or_attr,
-    context::{CompletionContext, PathCompletionCtx, PathKind, Qualified},
+    context::{AttrCtx, CompletionContext, PathCompletionCtx, Qualified},
     item::CompletionItem,
     Completions,
 };
@@ -28,7 +27,7 @@ mod derive;
 mod lint;
 mod repr;
 
-pub(crate) use self::derive::complete_derive;
+pub(crate) use self::derive::complete_derive_path;
 
 /// Complete inputs to known builtin attributes as well as derive attributes
 pub(crate) fn complete_known_attribute_input(
@@ -69,19 +68,13 @@ pub(crate) fn complete_known_attribute_input(
     Some(())
 }
 
-pub(crate) fn complete_attribute(
+pub(crate) fn complete_attribute_path(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    path_ctx: &PathCompletionCtx,
+    PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    &AttrCtx { kind, annotated_item_kind }: &AttrCtx,
 ) {
-    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),
-        _ => return,
-    };
+    let is_inner = kind == AttrKind::Inner;
 
     match qualified {
         Qualified::With {
@@ -94,8 +87,14 @@ pub(crate) fn complete_attribute(
             }
 
             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);
+                match def {
+                    hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => {
+                        acc.add_macro(ctx, m, name)
+                    }
+                    hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
+                        acc.add_module(ctx, m, name)
+                    }
+                    _ => (),
                 }
             }
             return;
@@ -104,10 +103,12 @@ pub(crate) fn complete_attribute(
         Qualified::Absolute => acc.add_crate_roots(ctx),
         // only show modules in a fresh UseTree
         Qualified::No => {
-            ctx.process_all_names(&mut |name, def| {
-                if let Some(def) = module_or_attr(ctx.db, def) {
-                    acc.add_resolution(ctx, name, def);
+            ctx.process_all_names(&mut |name, def| match def {
+                hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => {
+                    acc.add_macro(ctx, m, name)
                 }
+                hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
+                _ => (),
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
diff --git a/crates/ide-completion/src/completions/attribute/derive.rs b/crates/ide-completion/src/completions/attribute/derive.rs
index 0927d2f7643..0e10f381532 100644
--- a/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/crates/ide-completion/src/completions/attribute/derive.rs
@@ -5,23 +5,17 @@ use itertools::Itertools;
 use syntax::SmolStr;
 
 use crate::{
-    context::{CompletionContext, PathCompletionCtx, PathKind, Qualified},
+    context::{CompletionContext, ExistingDerives, PathCompletionCtx, Qualified},
     item::CompletionItem,
     Completions,
 };
 
-pub(crate) fn complete_derive(
+pub(crate) fn complete_derive_path(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    path_ctx: &PathCompletionCtx,
+    PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    existing_derives: &ExistingDerives,
 ) {
-    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 {
@@ -35,15 +29,14 @@ pub(crate) fn complete_derive(
             }
 
             for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
-                let add_def = match def {
-                    ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
-                        !existing_derives.contains(&mac) && mac.is_derive(ctx.db)
+                match def {
+                    ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac))
+                        if !existing_derives.contains(&mac) && mac.is_derive(ctx.db) =>
+                    {
+                        acc.add_macro(ctx, mac, name)
                     }
-                    ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
-                    _ => false,
-                };
-                if add_def {
-                    acc.add_resolution(ctx, name, def);
+                    ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
+                    _ => (),
                 }
             }
         }
@@ -57,8 +50,8 @@ pub(crate) fn complete_derive(
                     {
                         mac
                     }
-                    ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => {
-                        return acc.add_resolution(ctx, name, def);
+                    ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
+                        return acc.add_module(ctx, m, name);
                     }
                     _ => return,
                 };
@@ -66,7 +59,7 @@ pub(crate) fn complete_derive(
                 match (core, mac.module(ctx.db).krate()) {
                     // show derive dependencies for `core`/`std` derives
                     (Some(core), mac_krate) if core == mac_krate => {}
-                    _ => return acc.add_resolution(ctx, name, def),
+                    _ => return acc.add_macro(ctx, mac, name),
                 };
 
                 let name_ = name.to_smol_str();
@@ -99,7 +92,7 @@ pub(crate) fn complete_derive(
                         item.lookup_by(lookup);
                         item.add_to(acc);
                     }
-                    None => acc.add_resolution(ctx, name, def),
+                    None => acc.add_macro(ctx, mac, name),
                 }
             });
             acc.add_nameref_keywords_with_colon(ctx);
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index da26c2ad682..a8a57c0c7dd 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -3,9 +3,7 @@
 use ide_db::FxHashSet;
 
 use crate::{
-    context::{
-        CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind, Qualified,
-    },
+    context::{CompletionContext, DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, Qualified},
     CompletionItem, CompletionItemKind, Completions,
 };
 
@@ -42,16 +40,22 @@ pub(crate) fn complete_undotted_self(
     acc: &mut Completions,
     ctx: &CompletionContext,
     path_ctx: &PathCompletionCtx,
+    expr_ctx: &ExprCtx,
 ) {
     if !ctx.config.enable_self_on_the_fly {
         return;
     }
-    let self_param = match path_ctx {
-        PathCompletionCtx {
-            qualified: Qualified::No,
-            kind: PathKind::Expr { self_param: Some(self_param), .. },
-            ..
-        } if path_ctx.is_trivial_path() && ctx.qualifier_ctx.none() => self_param,
+    if !path_ctx.is_trivial_path() {
+        return;
+    }
+    if !ctx.qualifier_ctx.none() {
+        return;
+    }
+    if !matches!(path_ctx.qualified, Qualified::No) {
+        return;
+    }
+    let self_param = match expr_ctx {
+        ExprCtx { self_param: Some(self_param), .. } => self_param,
         _ => return,
     };
 
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index 83ecb51aaab..84ae596a8d0 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -4,61 +4,34 @@ use hir::ScopeDef;
 use ide_db::FxHashSet;
 
 use crate::{
-    context::{PathCompletionCtx, PathKind, Qualified},
+    context::{ExprCtx, PathCompletionCtx, Qualified},
     CompletionContext, Completions,
 };
 
 pub(crate) fn complete_expr_path(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    path_ctx: &PathCompletionCtx,
-) {
-    let _p = profile::span("complete_expr_path");
-    if !ctx.qualifier_ctx.none() {
-        return;
-    }
-    let (
-        qualified,
+    PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    &ExprCtx {
         in_block_expr,
         in_loop_body,
-        is_func_update,
         after_if_expr,
-        wants_mut_token,
         in_condition,
-        ty,
         incomplete_let,
-        impl_,
-    ) = match path_ctx {
-        &PathCompletionCtx {
-            kind:
-                PathKind::Expr {
-                    in_block_expr,
-                    in_loop_body,
-                    after_if_expr,
-                    in_condition,
-                    incomplete_let,
-                    ref ref_expr_parent,
-                    ref is_func_update,
-                    ref innermost_ret_ty,
-                    ref impl_,
-                    ..
-                },
-            ref qualified,
-            ..
-        } => (
-            qualified,
-            in_block_expr,
-            in_loop_body,
-            is_func_update.is_some(),
-            after_if_expr,
-            ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false),
-            in_condition,
-            innermost_ret_ty,
-            incomplete_let,
-            impl_,
-        ),
-        _ => return,
-    };
+        ref ref_expr_parent,
+        ref is_func_update,
+        ref innermost_ret_ty,
+        ref impl_,
+        ..
+    }: &ExprCtx,
+) {
+    let _p = profile::span("complete_expr_path");
+    if !ctx.qualifier_ctx.none() {
+        return;
+    }
+
+    let wants_mut_token =
+        ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
 
     let scope_def_applicable = |def| {
         use hir::{GenericParam::*, ModuleDef::*};
@@ -230,7 +203,7 @@ pub(crate) fn complete_expr_path(
                 }
             });
 
-            if !is_func_update {
+            if is_func_update.is_none() {
                 let mut add_keyword =
                     |kw, snippet| acc.add_keyword_snippet_expr(ctx, kw, snippet, incomplete_let);
 
@@ -270,7 +243,7 @@ pub(crate) fn complete_expr_path(
                     }
                 }
 
-                if let Some(ty) = ty {
+                if let Some(ty) = innermost_ret_ty {
                     add_keyword(
                         "return",
                         match (in_block_expr, ty.is_unit()) {
diff --git a/crates/ide-completion/src/completions/field.rs b/crates/ide-completion/src/completions/field.rs
index 6d346c5fd4b..738c24574c9 100644
--- a/crates/ide-completion/src/completions/field.rs
+++ b/crates/ide-completion/src/completions/field.rs
@@ -1,7 +1,7 @@
 //! Completion of field list position.
 
 use crate::{
-    context::{NameContext, NameKind, PathCompletionCtx, PathKind, Qualified, TypeLocation},
+    context::{PathCompletionCtx, Qualified},
     CompletionContext, Completions,
 };
 
@@ -10,37 +10,31 @@ pub(crate) fn complete_field_list_tuple_variant(
     ctx: &CompletionContext,
     path_ctx: &PathCompletionCtx,
 ) {
+    if ctx.qualifier_ctx.vis_node.is_some() {
+        return;
+    }
     match path_ctx {
         PathCompletionCtx {
             has_macro_bang: false,
             qualified: Qualified::No,
             parent: None,
-            kind: PathKind::Type { location: TypeLocation::TupleField },
             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");
-            }
-        }
-        _ => (),
-    }
-}
-
-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");
         }
+        _ => (),
+    }
+}
+
+pub(crate) fn complete_field_list_record_variant(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)");
+        add_keyword("pub(super)", "pub(super)");
+        add_keyword("pub", "pub");
     }
 }
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs
index 941273fa971..e697e1971ea 100644
--- a/crates/ide-completion/src/completions/item_list.rs
+++ b/crates/ide-completion/src/completions/item_list.rs
@@ -1,34 +1,37 @@
 //! Completion of paths and keywords at item list position.
 
 use crate::{
-    completions::module_or_fn_macro,
-    context::{ItemListKind, PathCompletionCtx, PathKind, Qualified},
+    context::{ExprCtx, ItemListKind, PathCompletionCtx, Qualified},
     CompletionContext, Completions,
 };
 
 pub(crate) mod trait_impl;
 
-pub(crate) fn complete_item_list(
+pub(crate) fn complete_item_list_in_expr(
     acc: &mut Completions,
     ctx: &CompletionContext,
     path_ctx: &PathCompletionCtx,
+    expr_ctx: &ExprCtx,
+) {
+    if !expr_ctx.in_block_expr {
+        return;
+    }
+    if !path_ctx.is_trivial_path() {
+        return;
+    }
+    add_keywords(acc, ctx, None);
+}
+
+pub(crate) fn complete_item_list(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    kind: &ItemListKind,
 ) {
     let _p = profile::span("complete_item_list");
-    let qualified = match path_ctx {
-        PathCompletionCtx { kind: PathKind::Item { kind }, qualified, .. } => {
-            if path_ctx.is_trivial_path() {
-                add_keywords(acc, ctx, Some(kind));
-            }
-            qualified
-        }
-        PathCompletionCtx { kind: PathKind::Expr { in_block_expr: true, .. }, .. }
-            if path_ctx.is_trivial_path() =>
-        {
-            add_keywords(acc, ctx, None);
-            return;
-        }
-        _ => return,
-    };
+    if path_ctx.is_trivial_path() {
+        add_keywords(acc, ctx, Some(kind));
+    }
 
     match qualified {
         Qualified::With {
@@ -37,8 +40,14 @@ pub(crate) fn complete_item_list(
             ..
         } => {
             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);
+                match def {
+                    hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
+                        acc.add_macro(ctx, m, name)
+                    }
+                    hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
+                        acc.add_module(ctx, m, name)
+                    }
+                    _ => (),
                 }
             }
 
@@ -48,10 +57,12 @@ pub(crate) fn complete_item_list(
         }
         Qualified::Absolute => acc.add_crate_roots(ctx),
         Qualified::No if ctx.qualifier_ctx.none() => {
-            ctx.process_all_names(&mut |name, def| {
-                if let Some(def) = module_or_fn_macro(ctx.db, def) {
-                    acc.add_resolution(ctx, name, def);
+            ctx.process_all_names(&mut |name, def| match def {
+                hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
+                    acc.add_macro(ctx, m, name)
                 }
+                hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
+                _ => (),
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
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 58b894bdd43..972a7d2f211 100644
--- a/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -43,11 +43,8 @@ use syntax::{
 use text_edit::TextEdit;
 
 use crate::{
-    context::{
-        ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind, PathCompletionCtx,
-        PathKind,
-    },
-    CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, Completions,
+    context::PathCompletionCtx, CompletionContext, CompletionItem, CompletionItemKind,
+    CompletionRelevance, Completions,
 };
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -58,17 +55,36 @@ enum ImplCompletionKind {
     Const,
 }
 
-pub(crate) fn complete_trait_impl_name(
+pub(crate) fn complete_trait_impl_const(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    NameContext { name, kind, .. }: &NameContext,
+    name: &Option<ast::Name>,
+) -> Option<()> {
+    complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::Const)
+}
+
+pub(crate) fn complete_trait_impl_type_alias(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name: &Option<ast::Name>,
+) -> Option<()> {
+    complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::TypeAlias)
+}
+
+pub(crate) fn complete_trait_impl_fn(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name: &Option<ast::Name>,
+) -> Option<()> {
+    complete_trait_impl_name(acc, ctx, name, ImplCompletionKind::Fn)
+}
+
+fn complete_trait_impl_name(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    name: &Option<ast::Name>,
+    kind: ImplCompletionKind,
 ) -> 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(),
@@ -86,34 +102,28 @@ pub(crate) fn complete_trait_impl_name(
     Some(())
 }
 
-pub(crate) fn complete_trait_impl_name_ref(
+pub(crate) fn complete_trait_impl_item_by_name(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    name_ref_ctx: &NameRefContext,
-) -> Option<()> {
-    match name_ref_ctx {
-        NameRefContext {
-            nameref,
-            kind:
-                NameRefKind::Path(
-                    path_ctx @ PathCompletionCtx {
-                        kind: PathKind::Item { kind: ItemListKind::TraitImpl(Some(impl_)) },
-                        ..
-                    },
-                ),
-        } if path_ctx.is_trivial_path() => complete_trait_impl(
+    path_ctx: &PathCompletionCtx,
+    name_ref: &Option<ast::NameRef>,
+    impl_: &Option<ast::Impl>,
+) {
+    if !path_ctx.is_trivial_path() {
+        return;
+    }
+    if let Some(impl_) = impl_ {
+        complete_trait_impl(
             acc,
             ctx,
             ImplCompletionKind::All,
-            match nameref {
+            match name_ref {
                 Some(name) => name.syntax().text_range(),
                 None => ctx.source_range(),
             },
             impl_,
-        ),
-        _ => (),
+        );
     }
-    Some(())
 }
 
 fn complete_trait_impl(
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 57d545ab8fe..7d8d3a9636d 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -4,7 +4,7 @@ use syntax::ast::{self, Item};
 
 use crate::{CompletionContext, Completions};
 
-pub(crate) fn complete_special_keywords(
+pub(crate) fn complete_for_and_where(
     acc: &mut Completions,
     ctx: &CompletionContext,
     keyword_item: &ast::Item,
@@ -60,8 +60,6 @@ mod tests {
                 kw fn
                 kw impl
                 kw trait
-                sn pd
-                sn ppd
             "#]],
         );
     }
diff --git a/crates/ide-completion/src/completions/mod_.rs b/crates/ide-completion/src/completions/mod_.rs
index 8dd1d1d8ac8..6f67c38dfde 100644
--- a/crates/ide-completion/src/completions/mod_.rs
+++ b/crates/ide-completion/src/completions/mod_.rs
@@ -9,21 +9,14 @@ use ide_db::{
 };
 use syntax::{ast, AstNode, SyntaxKind};
 
-use crate::{
-    context::{CompletionContext, NameContext, NameKind},
-    CompletionItem, Completions,
-};
+use crate::{context::CompletionContext, CompletionItem, Completions};
 
 /// Complete mod declaration, i.e. `mod $0;`
 pub(crate) fn complete_mod(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    name_ctx: &NameContext,
+    mod_under_caret: &ast::Module,
 ) -> 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() {
         return None;
     }
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 149acb3c1be..e2e8d3f205a 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -5,7 +5,7 @@ use ide_db::FxHashSet;
 use syntax::ast::Pat;
 
 use crate::{
-    context::{PathCompletionCtx, PathKind, PatternContext, PatternRefutability, Qualified},
+    context::{PathCompletionCtx, PatternContext, PatternRefutability, Qualified},
     CompletionContext, Completions,
 };
 
@@ -108,14 +108,11 @@ pub(crate) fn complete_pattern(
     });
 }
 
-pub(crate) fn pattern_path_completion(
+pub(crate) fn complete_pattern_path(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    PathCompletionCtx { qualified, kind, .. }: &PathCompletionCtx,
+    PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
 ) {
-    if !matches!(kind, PathKind::Pat { .. }) {
-        return;
-    }
     match qualified {
         Qualified::With { resolution: Some(resolution), is_super_chain, .. } => {
             if *is_super_chain {
diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs
index eaab4cb4eea..12c449bf352 100644
--- a/crates/ide-completion/src/completions/record.rs
+++ b/crates/ide-completion/src/completions/record.rs
@@ -6,7 +6,7 @@ use syntax::{
 };
 
 use crate::{
-    context::{PathCompletionCtx, PathKind, PatternContext, Qualified},
+    context::{ExprCtx, PathCompletionCtx, PatternContext, Qualified},
     CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
     CompletionRelevancePostfixMatch, Completions,
 };
@@ -20,7 +20,7 @@ pub(crate) fn complete_record_pattern_fields(
         complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat));
     }
 }
-pub(crate) fn complete_record_expr_fields_record_expr(
+pub(crate) fn complete_record_expr_fields(
     acc: &mut Completions,
     ctx: &CompletionContext,
     record_expr: &ast::RecordExpr,
@@ -85,13 +85,12 @@ pub(crate) fn complete_record_expr_func_update(
     acc: &mut Completions,
     ctx: &CompletionContext,
     path_ctx: &PathCompletionCtx,
+    expr_ctx: &ExprCtx,
 ) {
-    if let PathCompletionCtx {
-        kind: PathKind::Expr { is_func_update: Some(record_expr), .. },
-        qualified: Qualified::No,
-        ..
-    } = path_ctx
-    {
+    if !matches!(path_ctx.qualified, Qualified::No) {
+        return;
+    }
+    if let ExprCtx { is_func_update: Some(record_expr), .. } = expr_ctx {
         let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
 
         match ty.as_ref().and_then(|t| t.original.as_adt()) {
diff --git a/crates/ide-completion/src/completions/snippet.rs b/crates/ide-completion/src/completions/snippet.rs
index 48366987f40..9992a81fe07 100644
--- a/crates/ide-completion/src/completions/snippet.rs
+++ b/crates/ide-completion/src/completions/snippet.rs
@@ -4,7 +4,7 @@ use hir::Documentation;
 use ide_db::{imports::insert_use::ImportScope, SnippetCap};
 
 use crate::{
-    context::{ItemListKind, PathCompletionCtx, PathKind, Qualified},
+    context::{ExprCtx, ItemListKind, PathCompletionCtx, Qualified},
     item::Builder,
     CompletionContext, CompletionItem, CompletionItemKind, Completions, SnippetScope,
 };
@@ -19,15 +19,14 @@ pub(crate) fn complete_expr_snippet(
     acc: &mut Completions,
     ctx: &CompletionContext,
     path_ctx: &PathCompletionCtx,
+    &ExprCtx { in_block_expr, .. }: &ExprCtx,
 ) {
-    let &can_be_stmt = match path_ctx {
-        PathCompletionCtx {
-            qualified: Qualified::No,
-            kind: PathKind::Expr { in_block_expr, .. },
-            ..
-        } => in_block_expr,
-        _ => return,
-    };
+    if !matches!(path_ctx.qualified, Qualified::No) {
+        return;
+    }
+    if !ctx.qualifier_ctx.none() {
+        return;
+    }
 
     let cap = match ctx.config.snippet_cap {
         Some(it) => it,
@@ -38,9 +37,21 @@ pub(crate) fn complete_expr_snippet(
         add_custom_completions(acc, ctx, cap, SnippetScope::Expr);
     }
 
-    if can_be_stmt {
+    if in_block_expr {
         snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc);
         snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc);
+        let item = snippet(
+            ctx,
+            cap,
+            "macro_rules",
+            "\
+macro_rules! $1 {
+    ($2) => {
+        $0
+    };
+}",
+        );
+        item.add_to(acc);
     }
 }
 
@@ -48,21 +59,13 @@ pub(crate) fn complete_item_snippet(
     acc: &mut Completions,
     ctx: &CompletionContext,
     path_ctx: &PathCompletionCtx,
+    kind: &ItemListKind,
 ) {
-    let path_kind = match path_ctx {
-        PathCompletionCtx {
-            qualified: Qualified::No,
-            kind: kind @ (PathKind::Item { .. } | PathKind::Expr { in_block_expr: true, .. }),
-            ..
-        } => kind,
-        _ => return,
-    };
-    if !ctx.qualifier_ctx.none() {
+    if !matches!(path_ctx.qualified, Qualified::No) {
         return;
     }
-    if ctx.qualifier_ctx.vis_node.is_some() {
-        return; // technically we could do some of these snippet completions if we were to put the
-                // attributes before the vis node.
+    if !ctx.qualifier_ctx.none() {
+        return;
     }
     let cap = match ctx.config.snippet_cap {
         Some(it) => it,
@@ -74,8 +77,7 @@ pub(crate) fn complete_item_snippet(
     }
 
     // Test-related snippets shouldn't be shown in blocks.
-    if let PathKind::Item { kind: ItemListKind::SourceFile | ItemListKind::Module, .. } = path_kind
-    {
+    if let ItemListKind::SourceFile | ItemListKind::Module = kind {
         let mut item = snippet(
             ctx,
             cap,
@@ -106,10 +108,7 @@ fn ${1:feature}() {
         );
         item.lookup_by("tfn");
         item.add_to(acc);
-    }
-    if let PathKind::Item { kind: ItemListKind::SourceFile | ItemListKind::Module, .. }
-    | PathKind::Expr { .. } = path_kind
-    {
+
         let item = snippet(
             ctx,
             cap,
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index b8d172696d7..0f7ca758681 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -5,7 +5,7 @@ use ide_db::FxHashSet;
 use syntax::{ast, AstNode};
 
 use crate::{
-    context::{PathCompletionCtx, PathKind, Qualified, TypeAscriptionTarget, TypeLocation},
+    context::{PathCompletionCtx, Qualified, TypeAscriptionTarget, TypeLocation},
     render::render_type_inference,
     CompletionContext, Completions,
 };
@@ -13,17 +13,11 @@ use crate::{
 pub(crate) fn complete_type_path(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    path_ctx: &PathCompletionCtx,
+    PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    location: &TypeLocation,
 ) {
     let _p = profile::span("complete_type_path");
 
-    let (location, qualified) = match path_ctx {
-        PathCompletionCtx { kind: PathKind::Type { location }, qualified, .. } => {
-            (location, qualified)
-        }
-        _ => return,
-    };
-
     let scope_def_applicable = |def| {
         use hir::{GenericParam::*, ModuleDef::*};
         match def {
@@ -191,19 +185,16 @@ pub(crate) fn complete_type_path(
     }
 }
 
-pub(crate) fn complete_inferred_type(
+pub(crate) fn complete_ascribed_type(
     acc: &mut Completions,
     ctx: &CompletionContext,
     path_ctx: &PathCompletionCtx,
+    ascription: &TypeAscriptionTarget,
 ) -> 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 {
+    if !path_ctx.is_trivial_path() {
+        return None;
+    }
+    let x = match ascription {
         TypeAscriptionTarget::Let(pat) | TypeAscriptionTarget::FnParam(pat) => {
             ctx.sema.type_of_pat(pat.as_ref()?)
         }
diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs
index 2cdd93f95bd..f262355fc06 100644
--- a/crates/ide-completion/src/completions/use_.rs
+++ b/crates/ide-completion/src/completions/use_.rs
@@ -5,33 +5,17 @@ use ide_db::{FxHashSet, SymbolKind};
 use syntax::{ast, AstNode};
 
 use crate::{
-    context::{
-        CompletionContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind, Qualified,
-    },
+    context::{CompletionContext, PathCompletionCtx, Qualified},
     item::Builder,
     CompletionItem, CompletionItemKind, CompletionRelevance, Completions,
 };
 
-pub(crate) fn complete_use_tree(
+pub(crate) fn complete_use_path(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    name_ref_ctx: &NameRefContext,
+    PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx,
+    name_ref: &Option<ast::NameRef>,
 ) {
-    let (qualified, name_ref, use_tree_parent) = match name_ref_ctx {
-        NameRefContext {
-            kind:
-                NameRefKind::Path(PathCompletionCtx {
-                    kind: PathKind::Use,
-                    qualified,
-                    use_tree_parent,
-                    ..
-                }),
-            nameref,
-            ..
-        } => (qualified, nameref, use_tree_parent),
-        _ => return,
-    };
-
     match qualified {
         Qualified::With { path, resolution: Some(resolution), is_super_chain } => {
             if *is_super_chain {
@@ -112,8 +96,8 @@ pub(crate) fn complete_use_tree(
             cov_mark::hit!(unqualified_path_selected_only);
             ctx.process_all_names(&mut |name, res| {
                 match res {
-                    ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => {
-                        acc.add_resolution(ctx, name, res);
+                    ScopeDef::ModuleDef(hir::ModuleDef::Module(module)) => {
+                        acc.add_module(ctx, module, name);
                     }
                     ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
                         // exclude prelude enum
diff --git a/crates/ide-completion/src/completions/vis.rs b/crates/ide-completion/src/completions/vis.rs
index 18513039e67..30de0e94f7a 100644
--- a/crates/ide-completion/src/completions/vis.rs
+++ b/crates/ide-completion/src/completions/vis.rs
@@ -1,24 +1,16 @@
 //! Completion for visibility specifiers.
 
-use hir::ScopeDef;
-
 use crate::{
-    context::{CompletionContext, PathCompletionCtx, PathKind, Qualified},
+    context::{CompletionContext, PathCompletionCtx, Qualified},
     Completions,
 };
 
 pub(crate) fn complete_vis_path(
     acc: &mut Completions,
     ctx: &CompletionContext,
-    path_ctx: &PathCompletionCtx,
+    PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    &has_in_token: &bool,
 ) {
-    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: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
@@ -31,7 +23,7 @@ pub(crate) fn complete_vis_path(
             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()));
+                    acc.add_module(ctx, next, name);
                 }
             }
 
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 0c7c6ab5af6..8c73709f4ce 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -88,27 +88,16 @@ impl PathCompletionCtx {
 #[derive(Debug, PartialEq, Eq)]
 pub(super) enum PathKind {
     Expr {
-        in_block_expr: bool,
-        in_loop_body: bool,
-        after_if_expr: bool,
-        /// Whether this expression is the direct condition of an if or while expression
-        in_condition: bool,
-        incomplete_let: bool,
-        ref_expr_parent: Option<ast::RefExpr>,
-        is_func_update: Option<ast::RecordExpr>,
-        self_param: Option<hir::SelfParam>,
-        innermost_ret_ty: Option<hir::Type>,
-        impl_: Option<ast::Impl>,
+        expr_ctx: ExprCtx,
     },
     Type {
         location: TypeLocation,
     },
     Attr {
-        kind: AttrKind,
-        annotated_item_kind: Option<SyntaxKind>,
+        attr_ctx: AttrCtx,
     },
     Derive {
-        existing_derives: FxHashSet<hir::Macro>,
+        existing_derives: ExistingDerives,
     },
     /// Path in item position, that is inside an (Assoc)ItemList
     Item {
@@ -123,6 +112,29 @@ pub(super) enum PathKind {
     Use,
 }
 
+pub(crate) type ExistingDerives = FxHashSet<hir::Macro>;
+
+#[derive(Debug, PartialEq, Eq)]
+pub(crate) struct AttrCtx {
+    pub(crate) kind: AttrKind,
+    pub(crate) annotated_item_kind: Option<SyntaxKind>,
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub(crate) struct ExprCtx {
+    pub(crate) in_block_expr: bool,
+    pub(crate) in_loop_body: bool,
+    pub(crate) after_if_expr: bool,
+    /// Whether this expression is the direct condition of an if or while expression
+    pub(crate) in_condition: bool,
+    pub(crate) incomplete_let: bool,
+    pub(crate) ref_expr_parent: Option<ast::RefExpr>,
+    pub(crate) is_func_update: Option<ast::RecordExpr>,
+    pub(crate) self_param: Option<hir::SelfParam>,
+    pub(crate) innermost_ret_ty: Option<hir::Type>,
+    pub(crate) impl_: Option<ast::Impl>,
+}
+
 /// Original file ast nodes
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum TypeLocation {
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 9ceb60f90f1..551fa7fb865 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -11,10 +11,10 @@ use syntax::{
 };
 
 use crate::context::{
-    CompletionContext, DotAccess, DotAccessKind, IdentContext, ItemListKind, LifetimeContext,
-    LifetimeKind, NameContext, NameKind, NameRefContext, NameRefKind, ParamKind, PathCompletionCtx,
-    PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx, TypeAscriptionTarget,
-    TypeLocation, COMPLETION_MARKER,
+    AttrCtx, CompletionContext, DotAccess, DotAccessKind, ExprCtx, IdentContext, ItemListKind,
+    LifetimeContext, LifetimeKind, NameContext, NameKind, NameRefContext, NameRefKind, ParamKind,
+    PathCompletionCtx, PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx,
+    TypeAscriptionTarget, TypeLocation, COMPLETION_MARKER,
 };
 
 impl<'a> CompletionContext<'a> {
@@ -765,16 +765,18 @@ impl<'a> CompletionContext<'a> {
             let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());
 
             PathKind::Expr {
-                in_block_expr,
-                in_loop_body,
-                after_if_expr,
-                in_condition,
-                ref_expr_parent,
-                is_func_update,
-                innermost_ret_ty,
-                self_param,
-                incomplete_let,
-                impl_,
+                expr_ctx: ExprCtx {
+                    in_block_expr,
+                    in_loop_body,
+                    after_if_expr,
+                    in_condition,
+                    ref_expr_parent,
+                    is_func_update,
+                    innermost_ret_ty,
+                    self_param,
+                    incomplete_let,
+                    impl_,
+                },
             }
         };
         let make_path_kind_type = |ty: ast::Type| {
@@ -858,8 +860,10 @@ impl<'a> CompletionContext<'a> {
                             Some(attached.kind())
                         };
                         PathKind::Attr {
-                            kind,
-                            annotated_item_kind,
+                            attr_ctx: AttrCtx {
+                                kind,
+                                annotated_item_kind,
+                            }
                         }
                     },
                     ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
@@ -914,7 +918,7 @@ impl<'a> CompletionContext<'a> {
         if path_ctx.is_trivial_path() {
             // fetch the full expression that may have qualifiers attached to it
             let top_node = match path_ctx.kind {
-                PathKind::Expr { in_block_expr: true, .. } => {
+                PathKind::Expr { expr_ctx: ExprCtx { in_block_expr: true, .. } } => {
                     parent.ancestors().find(|it| ast::PathExpr::can_cast(it.kind())).and_then(|p| {
                         let parent = p.parent()?;
                         if ast::StmtList::can_cast(parent.kind()) {
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 27fe66e385a..90e2628439f 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -24,7 +24,9 @@ use text_edit::TextEdit;
 
 use crate::{
     completions::Completions,
-    context::{CompletionContext, IdentContext, NameKind, NameRefContext, NameRefKind},
+    context::{
+        CompletionContext, IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind,
+    },
 };
 
 pub use crate::{
@@ -151,10 +153,13 @@ pub fn completions(
 
     // prevent `(` from triggering unwanted completion noise
     if trigger_character == Some('(') {
-        if let IdentContext::NameRef(NameRefContext { kind: NameRefKind::Path(path_ctx), .. }) =
-            &ctx.ident_ctx
-        {
-            completions::vis::complete_vis_path(&mut completions, ctx, path_ctx);
+        if let IdentContext::NameRef(NameRefContext { kind, .. }) = &ctx.ident_ctx {
+            if let NameRefKind::Path(
+                path_ctx @ PathCompletionCtx { kind: PathKind::Vis { has_in_token }, .. },
+            ) = kind
+            {
+                completions::vis::complete_vis_path(&mut completions, ctx, path_ctx, has_in_token);
+            }
         }
         // prevent `(` from triggering unwanted completion noise
         return Some(completions);
@@ -164,62 +169,9 @@ pub fn 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::item_list::trait_impl::complete_trait_impl_name(acc, ctx, name_ctx);
-                completions::mod_::complete_mod(acc, ctx, name_ctx);
-                if let NameKind::IdentPat(pattern_ctx) = &name_ctx.kind {
-                    completions::flyimport::import_on_the_fly_pat(acc, ctx, pattern_ctx);
-                    completions::fn_param::complete_fn_param(acc, ctx, pattern_ctx);
-                    completions::pattern::complete_pattern(acc, ctx, pattern_ctx);
-                    completions::record::complete_record_pattern_fields(acc, ctx, pattern_ctx);
-                }
-            }
-            IdentContext::NameRef(name_ctx @ NameRefContext { kind, .. }) => {
-                completions::item_list::trait_impl::complete_trait_impl_name_ref(
-                    acc, ctx, name_ctx,
-                );
-                completions::use_::complete_use_tree(acc, ctx, name_ctx);
-
-                match kind {
-                    NameRefKind::Path(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::expr::complete_expr_path(acc, ctx, path_ctx);
-                        completions::field::complete_field_list_tuple_variant(acc, ctx, path_ctx);
-                        completions::flyimport::import_on_the_fly_path(acc, ctx, path_ctx);
-                        completions::item_list::complete_item_list(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::record::complete_record_expr_func_update(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);
-                    }
-                    NameRefKind::DotAccess(dot_access) => {
-                        completions::flyimport::import_on_the_fly_dot(acc, ctx, dot_access);
-                        completions::dot::complete_dot(acc, ctx, dot_access);
-                        completions::postfix::complete_postfix(acc, ctx, dot_access);
-                    }
-                    NameRefKind::Keyword(item) => {
-                        completions::keyword::complete_special_keywords(acc, ctx, item);
-                    }
-                    NameRefKind::RecordExpr(record_expr) => {
-                        completions::record::complete_record_expr_fields_record_expr(
-                            acc,
-                            ctx,
-                            record_expr,
-                        );
-                    }
-                    NameRefKind::Pattern(pattern_ctx) => {
-                        completions::flyimport::import_on_the_fly_pat(acc, ctx, pattern_ctx);
-                        completions::fn_param::complete_fn_param(acc, ctx, pattern_ctx);
-                        completions::pattern::complete_pattern(acc, ctx, pattern_ctx);
-                        completions::record::complete_record_pattern_fields(acc, ctx, pattern_ctx);
-                    }
-                }
+            IdentContext::Name(name_ctx) => completions::complete_name(acc, ctx, name_ctx),
+            IdentContext::NameRef(name_ref_ctx) => {
+                completions::complete_name_ref(acc, ctx, name_ref_ctx)
             }
             IdentContext::Lifetime(lifetime_ctx) => {
                 completions::lifetime::complete_label(acc, ctx, lifetime_ctx);
diff --git a/crates/ide-completion/src/snippet.rs b/crates/ide-completion/src/snippet.rs
index 82632f440d4..a6bb3d0648b 100644
--- a/crates/ide-completion/src/snippet.rs
+++ b/crates/ide-completion/src/snippet.rs
@@ -2,8 +2,6 @@
 //!
 //! Actual logic is implemented in [`crate::completions::postfix`] and [`crate::completions::snippet`] respectively.
 
-use std::ops::Deref;
-
 // Feature: User Snippet Completions
 //
 // rust-analyzer allows the user to define custom (postfix)-snippets that may depend on items to be accessible for the current scope to be applicable.
@@ -146,8 +144,8 @@ impl Snippet {
         let (requires, snippet, description) = validate_snippet(snippet, description, requires)?;
         Some(Snippet {
             // Box::into doesn't work as that has a Copy bound 😒
-            postfix_triggers: postfix_triggers.iter().map(Deref::deref).map(Into::into).collect(),
-            prefix_triggers: prefix_triggers.iter().map(Deref::deref).map(Into::into).collect(),
+            postfix_triggers: postfix_triggers.iter().map(String::as_str).map(Into::into).collect(),
+            prefix_triggers: prefix_triggers.iter().map(String::as_str).map(Into::into).collect(),
             scope,
             snippet,
             description,