Repository: rust-analyzer/rust-analyzer
Pull request #10650 (2021-10-27 16:06:40)

minor: Bump deps


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index eff2545268..15d49b1dc9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -55,9 +55,9 @@ checksum = "577b08a4acd7b99869f863c50011b01eb73424ccc798ecd996f2e24817adfca7"
 
 [[package]]
 name = "arrayvec"
-version = "0.7.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd"
+checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
 
 [[package]]
 name = "atty"
@@ -78,16 +78,16 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "backtrace"
-version = "0.3.61"
+version = "0.3.62"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01"
+checksum = "091bcdf2da9950f96aa522681ce805e6857f6ca8df73833d35736ab2dc78e152"
 dependencies = [
  "addr2line",
  "cc",
  "cfg-if",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.27.1",
  "rustc-demangle",
 ]
 
@@ -99,7 +99,6 @@ dependencies = [
  "profile",
  "rustc-hash",
  "salsa",
- "stdx",
  "syntax",
  "test_utils",
  "tt",
@@ -132,9 +131,9 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.14.0"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
+checksum = "ba2ae6de944143141f6155a473a6b02f66c7c3f9f47316f802f80204ebfe6e12"
 dependencies = [
  "camino",
  "cargo-platform",
@@ -171,9 +170,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.71.0"
+version = "0.72.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "059cce4ba41e57dd82f55b348d3e83cb30fd142479d00287f08c4ae66f9e7197"
+checksum = "50947a8c71b9a6ee75d6c3b74eb320f58668f872a5ca1347a2b664989fbc8ac8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -183,9 +182,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.71.0"
+version = "0.72.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0f9b041f3fcc136dbf8a92cef5f6ac743f9800467763502f5924349b781cbe0"
+checksum = "39fba0a2f05527fb93c5039803c1f1ffaff5d6cebdff936386e1a5cbe7646283"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -194,9 +193,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.71.0"
+version = "0.72.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1dd77179b3310dea3838b73e0f5990fcf4d1c00bfd2bc43d984faa8d2783ff1"
+checksum = "d01108bc48af1d40e69b3b7f6923323e904c32476d4974750c474c1f94343e5c"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -207,9 +206,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.71.0"
+version = "0.72.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c8ff6810c6bcac76950d1d292f71862e5757f483b8745a9186e649076b913be"
+checksum = "ff759b94bbb114254ba01b7a7459f8fa78ae98801a814946ce7ed6d5973c8a06"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -747,9 +746,9 @@ dependencies = [
 
 [[package]]
 name = "instant"
-version = "0.1.11"
+version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
 dependencies = [
  "cfg-if",
 ]
@@ -807,9 +806,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.103"
+version = "0.2.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
+checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
 
 [[package]]
 name = "libloading"
@@ -953,9 +952,9 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.7.13"
+version = "0.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
+checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
 dependencies = [
  "libc",
  "log",
@@ -1019,6 +1018,15 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "object"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "once_cell"
 version = "1.8.0"
@@ -1116,9 +1124,9 @@ checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.30"
+version = "1.0.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
+checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
 dependencies = [
  "unicode-xid",
 ]
@@ -1128,7 +1136,7 @@ name = "proc_macro_api"
 version = "0.0.0"
 dependencies = [
  "memmap2",
- "object",
+ "object 0.26.2",
  "paths",
  "profile",
  "serde",
@@ -1147,7 +1155,7 @@ dependencies = [
  "libloading",
  "mbe",
  "memmap2",
- "object",
+ "object 0.26.2",
  "paths",
  "proc_macro_api",
  "proc_macro_test",
@@ -1530,9 +1538,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.80"
+version = "1.0.81"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
+checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/crates/base_db/Cargo.toml b/crates/base_db/Cargo.toml
index 5ba8255ddd..20a4b111e3 100644
--- a/crates/base_db/Cargo.toml
+++ b/crates/base_db/Cargo.toml
@@ -14,7 +14,6 @@ salsa = "0.17.0-pre.2"
 rustc-hash = "1.1.0"
 
 syntax = { path = "../syntax", version = "0.0.0" }
-stdx = { path = "../stdx", version = "0.0.0" }
 cfg = { path = "../cfg", version = "0.0.0" }
 profile = { path = "../profile", version = "0.0.0" }
 tt = { path = "../tt", version = "0.0.0" }
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 84e295e014..44d3b7ca5b 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -270,7 +270,7 @@ fn test_proc_macros(proc_macros: &[String]) -> (Vec<ProcMacro>, String) {
 pub fn identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
     item
 }
-#[proc_macro_derive(DeriveIdentity)]
+#[proc_macro_derive(derive_identity)]
 pub fn derive_identity(item: TokenStream) -> TokenStream {
     item
 }
@@ -290,7 +290,7 @@ pub fn mirror(input: TokenStream) -> TokenStream {
             expander: Arc::new(IdentityProcMacroExpander),
         },
         ProcMacro {
-            name: "DeriveIdentity".into(),
+            name: "derive_identity".into(),
             kind: crate::ProcMacroKind::CustomDerive,
             expander: Arc::new(IdentityProcMacroExpander),
         },
@@ -306,7 +306,7 @@ pub fn mirror(input: TokenStream) -> TokenStream {
         },
     ]
     .into_iter()
-    .filter(|pm| proc_macros.iter().any(|name| name == &stdx::to_lower_snake_case(&pm.name)))
+    .filter(|pm| proc_macros.iter().any(|name| name == pm.name))
     .collect();
     (proc_macros, source.into())
 }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 9c6531da20..17b901d5f8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1623,12 +1623,7 @@ impl MacroDef {
     pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
         match self.source(db)?.value {
             Either::Left(it) => it.name().map(|it| it.as_name()),
-            Either::Right(_) => {
-                let krate = self.id.krate;
-                let def_map = db.crate_def_map(krate);
-                let (_, name) = def_map.exported_proc_macros().find(|&(id, _)| id == self.id)?;
-                Some(name)
-            }
+            Either::Right(it) => it.name().map(|it| it.as_name()),
         }
     }
 
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 877d385fbd..20e2481af6 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -299,14 +299,8 @@ impl SourceToDefCtx<'_, '_> {
         dyn_map[keys::CONST_PARAM].get(&src).copied()
     }
 
+    // FIXME: use DynMap as well?
     pub(super) fn macro_to_def(&mut self, src: InFile<ast::Macro>) -> Option<MacroDefId> {
-        let makro = self.dyn_map(src.as_ref()).and_then(|it| it[keys::MACRO].get(&src).copied());
-        if let res @ Some(_) = makro {
-            return res;
-        }
-
-        // Not all macros are recorded in the dyn map, only the ones behaving like items, so fall back
-        // for the non-item like definitions.
         let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
         let ast_id = AstId::new(src.file_id, file_ast_id.upcast());
         let kind = MacroDefKind::Declarative(ast_id);
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index 1baf74c512..6d63570428 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -101,17 +101,6 @@ impl ChildBySource for ModuleId {
 impl ChildBySource for ItemScope {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         self.declarations().for_each(|item| add_module_def(db, file_id, res, item));
-        self.macros().for_each(|(_, makro)| {
-            let ast_id = makro.ast_id();
-            if ast_id.either(|it| it.file_id, |it| it.file_id) == file_id {
-                let src = match ast_id {
-                    Either::Left(ast_id) => ast_id.with_value(ast_id.to_node(db.upcast())),
-                    // FIXME: Do we need to add proc-macros into a PROCMACRO dynmap here?
-                    Either::Right(_fn) => return,
-                };
-                res[keys::MACRO].insert(src, makro);
-            }
-        });
         self.unnamed_consts().for_each(|konst| {
             let src = konst.lookup(db).source(db);
             res[keys::CONST].insert(src, konst);
diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs
index 07c4d083d6..c554540391 100644
--- a/crates/hir_def/src/keys.rs
+++ b/crates/hir_def/src/keys.rs
@@ -31,7 +31,7 @@ pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
 pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new();
 pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new();
 
-pub const MACRO: Key<ast::Macro, MacroDefId> = Key::new();
+pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new();
 pub const ATTR_MACRO: Key<ast::Item, MacroCallId> = Key::new();
 pub const DERIVE_MACRO: Key<ast::Attr, Box<[MacroCallId]>> = Key::new();
 
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index d0b8248a34..37c57ea63d 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -103,7 +103,7 @@ pub struct DefMap {
     /// Side table with additional proc. macro info, for use by name resolution in downstream
     /// crates.
     ///
-    /// (the primary purpose is to resolve derive helpers and fetch a proc-macros name)
+    /// (the primary purpose is to resolve derive helpers)
     exported_proc_macros: FxHashMap<MacroDefId, ProcMacroDef>,
 
     edition: Edition,
@@ -279,9 +279,7 @@ impl DefMap {
     pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
         self.modules.iter()
     }
-    pub fn exported_proc_macros(&self) -> impl Iterator<Item = (MacroDefId, Name)> + '_ {
-        self.exported_proc_macros.iter().map(|(id, def)| (*id, def.name.clone()))
-    }
+
     pub fn root(&self) -> LocalModuleId {
         self.root
     }
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 0349754fba..b048f46f9c 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1907,7 +1907,7 @@ impl ModCollector<'_, '_> {
         let mac = &self.item_tree[id];
         let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
 
-        // Case 1: builtin macros
+        // Case 1: bulitin macros
         let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
         if attrs.by_key("rustc_builtin_macro").exists() {
             let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 0225ab425f..5022642b0c 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -63,8 +63,8 @@ impl Name {
     /// Ideally, we want a `gensym` semantics for missing names -- each missing
     /// name is equal only to itself. It's not clear how to implement this in
     /// salsa though, so we punt on that bit for a moment.
-    pub const fn missing() -> Name {
-        Name::new_inline("[missing name]")
+    pub fn missing() -> Name {
+        Name::new_text("[missing name]".into())
     }
 
     /// Returns the tuple index this name represents if it is a tuple field.
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs
index d68794eb98..e8e1d99e80 100644
--- a/crates/hir_expand/src/proc_macro.rs
+++ b/crates/hir_expand/src/proc_macro.rs
@@ -1,9 +1,8 @@
 //! Proc Macro Expander stub
 
-use base_db::{CrateId, ProcMacroExpansionError, ProcMacroId, ProcMacroKind};
-use mbe::ExpandResult;
-
 use crate::db::AstDatabase;
+use base_db::{CrateId, ProcMacroExpansionError, ProcMacroId};
+use mbe::ExpandResult;
 
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
 pub struct ProcMacroExpander {
@@ -37,29 +36,20 @@ impl ProcMacroExpander {
                 let krate_graph = db.crate_graph();
                 let proc_macro = match krate_graph[self.krate].proc_macro.get(id.0 as usize) {
                     Some(proc_macro) => proc_macro,
-                    None => return ExpandResult::str_err("No proc-macro found.".to_string()),
+                    None => return ExpandResult::str_err("No derive macro found.".to_string()),
                 };
 
                 // Proc macros have access to the environment variables of the invoking crate.
                 let env = &krate_graph[calling_crate].env;
-                match proc_macro.expander.expand(tt, attr_arg, env) {
-                    Ok(t) => ExpandResult::ok(t),
-                    Err(err) => match err {
-                        // Don't discard the item in case something unexpected happened while expanding attributes
-                        ProcMacroExpansionError::System(text)
-                            if proc_macro.kind == ProcMacroKind::Attr =>
-                        {
-                            ExpandResult {
-                                value: tt.clone(),
-                                err: Some(mbe::ExpandError::Other(text)),
-                            }
-                        }
-                        ProcMacroExpansionError::System(text)
-                        | ProcMacroExpansionError::Panic(text) => {
-                            ExpandResult::only_err(mbe::ExpandError::Other(text))
-                        }
-                    },
-                }
+
+                proc_macro
+                    .expander
+                    .expand(tt, attr_arg, env)
+                    .map_err(|err| match err {
+                        ProcMacroExpansionError::Panic(text) => mbe::ExpandError::Other(text),
+                        ProcMacroExpansionError::System(text) => mbe::ExpandError::Other(text),
+                    })
+                    .into()
             }
             None => ExpandResult::only_err(mbe::ExpandError::UnresolvedProcMacro),
         }
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 14ef3e52ce..d0f22cdae3 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -18,9 +18,9 @@ ena = "0.14.0"
 tracing = "0.1"
 rustc-hash = "1.1.0"
 scoped-tls = "1"
-chalk-solve = { version = "0.71", default-features = false }
-chalk-ir = "0.71"
-chalk-recursive = { version = "0.71", default-features = false }
+chalk-solve = { version = "0.72", default-features = false }
+chalk-ir = "0.72"
+chalk-recursive = { version = "0.72", default-features = false }
 la-arena = { version = "0.3.0", path = "../../lib/arena" }
 once_cell = { version = "1.5.0" }
 
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 8c47b809b9..c184b014ba 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -4,7 +4,7 @@ mod intra_doc_links;
 
 use either::Either;
 use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
-use pulldown_cmark_to_cmark::{cmark_with_options, Options as CMarkOptions};
+use pulldown_cmark_to_cmark::{cmark_with_options, Options as CmarkOptions};
 use stdx::format_to;
 use url::Url;
 
@@ -65,7 +65,7 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin
         doc,
         &mut out,
         None,
-        CMarkOptions { code_block_backticks: 3, ..Default::default() },
+        CmarkOptions { code_block_backticks: 3, ..Default::default() },
     )
     .ok();
     out
@@ -103,7 +103,7 @@ pub(crate) fn remove_links(markdown: &str) -> String {
         doc,
         &mut out,
         None,
-        CMarkOptions { code_block_backticks: 3, ..Default::default() },
+        CmarkOptions { code_block_backticks: 3, ..Default::default() },
     )
     .ok();
     out
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 1edb17739b..1f0b9aaaa1 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1371,7 +1371,6 @@ impl Twait for Stwuct {
     fn goto_def_derive_input() {
         check(
             r#"
-//- minicore:derive
 #[rustc_builtin_macro]
 pub macro Copy {}
        // ^^^^
@@ -1381,7 +1380,6 @@ struct Foo;
         );
         check(
             r#"
-//- minicore:derive
 mod foo {
     #[rustc_builtin_macro]
     pub macro Copy {}
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 75249a959d..5e98ac1756 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -266,10 +266,12 @@ enum E { X(Foo) }
     fn derives() {
         check_all_ranges(
             r#"
-//- minicore:derive
 #[rustc_builtin_macro]
 pub macro Copy {}
         //^^^^
+#[rustc_builtin_macro]
+pub macro derive {}
+        //^^^^^^
 #[derive(Copy)]
 //^^^^^^ ^^^^
 struct Hello(i32);
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 2bf83da4df..1285c2f846 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -3,7 +3,7 @@
 use hir::{AsAssocItem, HasVisibility, Semantics};
 use ide_db::{
     defs::{Definition, NameClass, NameRefClass},
-    helpers::{try_resolve_derive_input, FamousDefs},
+    helpers::{try_resolve_derive_input_at, FamousDefs},
     RootDatabase, SymbolKind,
 };
 use rustc_hash::FxHashMap;
@@ -56,8 +56,8 @@ fn token(
             T![?] => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow,
             IDENT if parent_matches::<ast::TokenTree>(&token) => {
                 if let Some(attr) = token.ancestors().nth(2).and_then(ast::Attr::cast) {
-                    match try_resolve_derive_input(sema, &attr, &ast::Ident::cast(token).unwrap()) {
-                        Some(res) => highlight_def(sema, krate, Definition::from(res)),
+                    match try_resolve_derive_input_at(sema, &attr, &token) {
+                        Some(makro) => highlight_def(sema, krate, Definition::Macro(makro)),
                         None => HlTag::None.into(),
                     }
                 } else {
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index a5858869c5..1ec3932a2d 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -3,7 +3,7 @@ use ide_db::helpers::{
     insert_use::{insert_use, ImportScope},
     mod_path_to_ast,
 };
-use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxElement};
+use syntax::{ast, AstNode, SyntaxNode};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
 
@@ -90,18 +90,9 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
         return None;
     }
 
-    let range = match &syntax_under_caret {
-        NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
-        NodeOrToken::Token(token) => token.text_range(),
-    };
+    let range = ctx.sema.original_range(&syntax_under_caret).range;
     let group_label = group_label(import_assets.import_candidate());
-    let scope = ImportScope::find_insert_use_container_with_macros(
-        &match syntax_under_caret {
-            NodeOrToken::Node(it) => it,
-            NodeOrToken::Token(it) => it.parent()?,
-        },
-        &ctx.sema,
-    )?;
+    let scope = ImportScope::find_insert_use_container_with_macros(&syntax_under_caret, &ctx.sema)?;
 
     // we aren't interested in different namespaces
     proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
@@ -124,24 +115,22 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
     Some(())
 }
 
-pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxElement)> {
+pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> {
     if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
         ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
-            .zip(Some(path_under_caret.syntax().clone().into()))
+            .zip(Some(path_under_caret.syntax().clone()))
     } else if let Some(method_under_caret) =
         ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
     {
         ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
-            .zip(Some(method_under_caret.syntax().clone().into()))
+            .zip(Some(method_under_caret.syntax().clone()))
     } else if let Some(pat) = ctx
         .find_node_at_offset_with_descend::<ast::IdentPat>()
         .filter(ast::IdentPat::is_simple_ident)
     {
-        ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone().into()))
+        ImportAssets::for_ident_pat(&pat, &ctx.sema).zip(Some(pat.syntax().clone()))
     } else {
-        // FIXME: Descend?
-        let ident = ctx.find_token_at_offset()?;
-        ImportAssets::for_derive_ident(&ctx.sema, &ident).zip(Some(ident.syntax().clone().into()))
+        None
     }
 }
 
@@ -1038,32 +1027,6 @@ mod foo {
 fn foo() {
     let Foo;
 }
-"#,
-        );
-    }
-
-    #[test]
-    fn works_in_derives() {
-        check_assist(
-            auto_import,
-            r#"
-//- minicore:derive
-mod foo {
-    #[rustc_builtin_macro]
-    pub macro Copy {}
-}
-#[derive(Copy$0)]
-struct Foo;
-"#,
-            r#"
-use foo::Copy;
-
-mod foo {
-    #[rustc_builtin_macro]
-    pub macro Copy {}
-}
-#[derive(Copy)]
-struct Foo;
 "#,
         );
     }
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index 23b642fcb1..29f2c785bc 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -9,7 +9,7 @@ use ide_db::RootDatabase;
 use syntax::{
     ast,
     ast::{make, HasArgList},
-    AstNode, NodeOrToken,
+    AstNode,
 };
 
 use crate::{
@@ -42,39 +42,32 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
         return None;
     }
 
-    let range = match &syntax_under_caret {
-        NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
-        NodeOrToken::Token(token) => token.text_range(),
-    };
+    let range = ctx.sema.original_range(&syntax_under_caret).range;
     let candidate = import_assets.import_candidate();
-    let qualify_candidate = match syntax_under_caret {
-        NodeOrToken::Node(syntax_under_caret) => match candidate {
-            ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => {
-                cov_mark::hit!(qualify_path_qualifier_start);
-                let path = ast::Path::cast(syntax_under_caret)?;
-                let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
-                QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
-            }
-            ImportCandidate::Path(_) => {
-                cov_mark::hit!(qualify_path_unqualified_name);
-                let path = ast::Path::cast(syntax_under_caret)?;
-                let generics = path.segment()?.generic_arg_list();
-                QualifyCandidate::UnqualifiedName(generics)
-            }
-            ImportCandidate::TraitAssocItem(_) => {
-                cov_mark::hit!(qualify_path_trait_assoc_item);
-                let path = ast::Path::cast(syntax_under_caret)?;
-                let (qualifier, segment) = (path.qualifier()?, path.segment()?);
-                QualifyCandidate::TraitAssocItem(qualifier, segment)
-            }
-            ImportCandidate::TraitMethod(_) => {
-                cov_mark::hit!(qualify_path_trait_method);
-                let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?;
-                QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
-            }
-        },
-        // derive attribute path
-        NodeOrToken::Token(_) => QualifyCandidate::UnqualifiedName(None),
+    let qualify_candidate = match candidate {
+        ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => {
+            cov_mark::hit!(qualify_path_qualifier_start);
+            let path = ast::Path::cast(syntax_under_caret)?;
+            let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
+            QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
+        }
+        ImportCandidate::Path(_) => {
+            cov_mark::hit!(qualify_path_unqualified_name);
+            let path = ast::Path::cast(syntax_under_caret)?;
+            let generics = path.segment()?.generic_arg_list();
+            QualifyCandidate::UnqualifiedName(generics)
+        }
+        ImportCandidate::TraitAssocItem(_) => {
+            cov_mark::hit!(qualify_path_trait_assoc_item);
+            let path = ast::Path::cast(syntax_under_caret)?;
+            let (qualifier, segment) = (path.qualifier()?, path.segment()?);
+            QualifyCandidate::TraitAssocItem(qualifier, segment)
+        }
+        ImportCandidate::TraitMethod(_) => {
+            cov_mark::hit!(qualify_path_trait_method);
+            let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?;
+            QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
+        }
     };
 
     // we aren't interested in different namespaces
@@ -1243,30 +1236,6 @@ fn main() {
     let test_struct = test_mod::TestStruct {};
     test_mod::TestTrait::test_method::<()>(&test_struct)
 }
-"#,
-        );
-    }
-
-    #[test]
-    fn works_in_derives() {
-        check_assist(
-            qualify_path,
-            r#"
-//- minicore:derive
-mod foo {
-    #[rustc_builtin_macro]
-    pub macro Copy {}
-}
-#[derive(Copy$0)]
-struct Foo;
-"#,
-            r#"
-mod foo {
-    #[rustc_builtin_macro]
-    pub macro Copy {}
-}
-#[derive(foo::Copy)]
-struct Foo;
 "#,
         );
     }
diff --git a/crates/ide_assists/src/handlers/replace_turbofish_with_explicit_type.rs b/crates/ide_assists/src/handlers/replace_turbofish_with_explicit_type.rs
deleted file mode 100644
index dc3c860d7e..0000000000
--- a/crates/ide_assists/src/handlers/replace_turbofish_with_explicit_type.rs
+++ /dev/null
@@ -1,243 +0,0 @@
-use syntax::{
-    ast::{Expr, GenericArg},
-    ast::{LetStmt, Type::InferType},
-    AstNode, TextRange,
-};
-
-use crate::{
-    assist_context::{AssistContext, Assists},
-    AssistId, AssistKind,
-};
-
-// Assist: replace_turbofish_with_explicit_type
-//
-// Converts `::<_>` to an explicit type assignment.
-//
-// ```
-// fn make<T>() -> T { ) }
-// fn main() {
-//     let a = make$0::<i32>();
-// }
-// ```
-// ->
-// ```
-// fn make<T>() -> T { ) }
-// fn main() {
-//     let a: i32 = make();
-// }
-// ```
-pub(crate) fn replace_turbofish_with_explicit_type(
-    acc: &mut Assists,
-    ctx: &AssistContext,
-) -> Option<()> {
-    let let_stmt = ctx.find_node_at_offset::<LetStmt>()?;
-
-    let initializer = let_stmt.initializer()?;
-
-    let generic_args = match &initializer {
-        Expr::MethodCallExpr(ce) => ce.generic_arg_list()?,
-        Expr::CallExpr(ce) => {
-            if let Expr::PathExpr(pe) = ce.expr()? {
-                pe.path()?.segment()?.generic_arg_list()?
-            } else {
-                cov_mark::hit!(not_applicable_if_non_path_function_call);
-                return None;
-            }
-        }
-        _ => {
-            cov_mark::hit!(not_applicable_if_non_function_call_initializer);
-            return None;
-        }
-    };
-
-    // Find range of ::<_>
-    let colon2 = generic_args.coloncolon_token()?;
-    let r_angle = generic_args.r_angle_token()?;
-    let turbofish_range = TextRange::new(colon2.text_range().start(), r_angle.text_range().end());
-
-    let turbofish_args: Vec<GenericArg> = generic_args.generic_args().into_iter().collect();
-
-    // Find type of ::<_>
-    if turbofish_args.len() != 1 {
-        cov_mark::hit!(not_applicable_if_not_single_arg);
-        return None;
-    }
-
-    // An improvement would be to check that this is correctly part of the return value of the
-    // function call, or sub in the actual return type.
-    let turbofish_type = &turbofish_args[0];
-
-    let initializer_start = initializer.syntax().text_range().start();
-    if ctx.offset() > turbofish_range.end() || ctx.offset() < initializer_start {
-        cov_mark::hit!(not_applicable_outside_turbofish);
-        return None;
-    }
-
-    if let None = let_stmt.colon_token() {
-        // If there's no colon in a let statement, then there is no explicit type.
-        // let x = fn::<...>();
-        let ident_range = let_stmt.pat()?.syntax().text_range();
-
-        return acc.add(
-            AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
-            "Replace turbofish with explicit type",
-            TextRange::new(initializer_start, turbofish_range.end()),
-            |builder| {
-                builder.insert(ident_range.end(), format!(": {}", turbofish_type));
-                builder.delete(turbofish_range);
-            },
-        );
-    } else if let Some(InferType(t)) = let_stmt.ty() {
-        // If there's a type inferrence underscore, we can offer to replace it with the type in
-        // the turbofish.
-        // let x: _ = fn::<...>();
-        let underscore_range = t.syntax().text_range();
-
-        return acc.add(
-            AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
-            "Replace `_` with turbofish type",
-            turbofish_range,
-            |builder| {
-                builder.replace(underscore_range, turbofish_type.to_string());
-                builder.delete(turbofish_range);
-            },
-        );
-    }
-
-    None
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
-
-    #[test]
-    fn replaces_turbofish_for_vec_string() {
-        check_assist(
-            replace_turbofish_with_explicit_type,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let a = make$0::<Vec<String>>();
-}
-"#,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let a: Vec<String> = make();
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn replaces_method_calls() {
-        // foo.make() is a method call which uses a different expr in the let initializer
-        check_assist(
-            replace_turbofish_with_explicit_type,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let a = foo.make$0::<Vec<String>>();
-}
-"#,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let a: Vec<String> = foo.make();
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn replace_turbofish_target() {
-        check_assist_target(
-            replace_turbofish_with_explicit_type,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let a = $0make::<Vec<String>>();
-}
-"#,
-            r#"make::<Vec<String>>"#,
-        );
-    }
-
-    #[test]
-    fn not_applicable_outside_turbofish() {
-        cov_mark::check!(not_applicable_outside_turbofish);
-        check_assist_not_applicable(
-            replace_turbofish_with_explicit_type,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let $0a = make::<Vec<String>>();
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn replace_inferred_type_placeholder() {
-        check_assist(
-            replace_turbofish_with_explicit_type,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let a: _ = make$0::<Vec<String>>();
-}
-"#,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let a: Vec<String> = make();
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn not_applicable_constant_initializer() {
-        cov_mark::check!(not_applicable_if_non_function_call_initializer);
-        check_assist_not_applicable(
-            replace_turbofish_with_explicit_type,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let a = "foo"$0;
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn not_applicable_non_path_function_call() {
-        cov_mark::check!(not_applicable_if_non_path_function_call);
-        check_assist_not_applicable(
-            replace_turbofish_with_explicit_type,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    $0let a = (|| {})();
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn non_applicable_multiple_generic_args() {
-        cov_mark::check!(not_applicable_if_not_single_arg);
-        check_assist_not_applicable(
-            replace_turbofish_with_explicit_type,
-            r#"
-fn make<T>() -> T {}
-fn main() {
-    let a = make$0::<Vec<String>, i32>();
-}
-"#,
-        );
-    }
-}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index 5d4c1532db..8f9ae6c154 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -175,7 +175,6 @@ mod handlers {
     mod replace_let_with_if_let;
     mod replace_qualified_name_with_use;
     mod replace_string_with_char;
-    mod replace_turbofish_with_explicit_type;
     mod split_import;
     mod sort_items;
     mod toggle_ignore;
@@ -258,7 +257,6 @@ mod handlers {
             replace_if_let_with_match::replace_if_let_with_match,
             replace_if_let_with_match::replace_match_with_if_let,
             replace_let_with_if_let::replace_let_with_if_let,
-            replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
             replace_qualified_name_with_use::replace_qualified_name_with_use,
             sort_items::sort_items,
             split_import::split_import,
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index 3e658c6e91..5f751d83a8 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -21,7 +21,7 @@ use hir::known;
 use ide_db::SymbolKind;
 
 use crate::{
-    item::Builder,
+    item::{Builder, CompletionKind},
     render::{
         const_::render_const,
         enum_variant::render_variant,
@@ -76,7 +76,8 @@ impl Completions {
     }
 
     pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext, keyword: &'static str) {
-        let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword);
+        let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), keyword);
+        item.kind(CompletionItemKind::Keyword);
         item.add_to(self);
     }
 
@@ -190,7 +191,9 @@ impl Completions {
     }
 
     pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) {
-        let item = CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), "'static");
+        let mut item =
+            CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static");
+        item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam));
         self.add(item.build());
     }
 
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 2482418ae6..119572923c 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -12,7 +12,7 @@ use syntax::{algo::non_trivia_sibling, ast, AstNode, Direction, SyntaxKind, T};
 
 use crate::{
     context::CompletionContext,
-    item::{CompletionItem, CompletionItemKind},
+    item::{CompletionItem, CompletionItemKind, CompletionKind},
     Completions,
 };
 
@@ -69,10 +69,11 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
 
     let add_completion = |attr_completion: &AttrCompletion| {
         let mut item = CompletionItem::new(
-            CompletionItemKind::Attribute,
+            CompletionKind::Attribute,
             ctx.source_range(),
             attr_completion.label,
         );
+        item.kind(CompletionItemKind::Attribute);
 
         if let Some(lookup) = attr_completion.lookup {
             item.lookup_by(lookup);
@@ -102,10 +103,11 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
         if let hir::ScopeDef::MacroDef(mac) = scope_def {
             if mac.kind() == hir::MacroKind::Attr {
                 let mut item = CompletionItem::new(
-                    CompletionItemKind::Attribute,
+                    CompletionKind::Attribute,
                     ctx.source_range(),
                     name.to_string(),
                 );
+                item.kind(CompletionItemKind::Attribute);
                 if let Some(docs) = mac.docs(ctx.sema.db) {
                     item.documentation(docs);
                 }
diff --git a/crates/ide_completion/src/completions/attribute/cfg.rs b/crates/ide_completion/src/completions/attribute/cfg.rs
index c83e1718ec..171babc698 100644
--- a/crates/ide_completion/src/completions/attribute/cfg.rs
+++ b/crates/ide_completion/src/completions/attribute/cfg.rs
@@ -5,14 +5,16 @@ use std::iter;
 use syntax::SyntaxKind;
 
 use crate::{
-    completions::Completions, context::CompletionContext, CompletionItem, CompletionItemKind,
+    completions::Completions, context::CompletionContext, item::CompletionKind, CompletionItem,
+    CompletionItemKind,
 };
 
 pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
     let add_completion = |item: &str| {
         let mut completion =
-            CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), item);
+            CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), item);
         completion.insert_text(format!(r#""{}""#, item));
+        completion.kind(CompletionItemKind::Attribute);
         acc.add(completion.build());
     };
 
@@ -33,7 +35,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
             if let Some(krate) = ctx.krate {
                 krate.potential_cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| {
                     let mut item = CompletionItem::new(
-                        CompletionItemKind::Attribute,
+                        CompletionKind::Attribute,
                         ctx.source_range(),
                         s.as_str(),
                     );
@@ -47,7 +49,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
             if let Some(krate) = ctx.krate {
                 krate.potential_cfg(ctx.db).get_cfg_keys().iter().for_each(|s| {
                     let item = CompletionItem::new(
-                        CompletionItemKind::Attribute,
+                        CompletionKind::Attribute,
                         ctx.source_range(),
                         s.as_str(),
                     );
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index 5c08d12ef2..e460a91102 100644
--- a/crates/ide_completion/src/completions/attribute/derive.rs
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -1,15 +1,14 @@
 //! Completion for derives
 use hir::{HasAttrs, MacroDef, MacroKind};
-use ide_db::helpers::{import_assets::ImportAssets, insert_use::ImportScope, FamousDefs};
+use ide_db::helpers::FamousDefs;
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
-use syntax::{ast, SyntaxKind};
+use syntax::ast;
 
 use crate::{
-    completions::flyimport::compute_fuzzy_completion_order_key,
     context::CompletionContext,
-    item::{CompletionItem, CompletionItemKind},
-    Completions, ImportEdit,
+    item::{CompletionItem, CompletionItemKind, CompletionKind},
+    Completions,
 };
 
 pub(super) fn complete_derive(
@@ -57,8 +56,8 @@ pub(super) fn complete_derive(
             _ => (&*name, None),
         };
 
-        let mut item =
-            CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), label);
+        let mut item = CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
+        item.kind(CompletionItemKind::Attribute);
         if let Some(docs) = mac.docs(ctx.db) {
             item.documentation(docs);
         }
@@ -67,8 +66,6 @@ pub(super) fn complete_derive(
         }
         item.add_to(acc);
     }
-
-    flyimport_attribute(ctx, acc);
 }
 
 fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
@@ -83,50 +80,6 @@ fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
     result
 }
 
-fn flyimport_attribute(ctx: &CompletionContext, acc: &mut Completions) -> Option<()> {
-    if ctx.token.kind() != SyntaxKind::IDENT {
-        return None;
-    };
-    let potential_import_name = ctx.token.to_string();
-    let module = ctx.scope.module()?;
-    let parent = ctx.token.parent()?;
-    let user_input_lowercased = potential_import_name.to_lowercase();
-    let import_assets = ImportAssets::for_fuzzy_path(
-        module,
-        None,
-        potential_import_name,
-        &ctx.sema,
-        parent.clone(),
-    )?;
-    let import_scope = ImportScope::find_insert_use_container_with_macros(&parent, &ctx.sema)?;
-    acc.add_all(
-        import_assets
-            .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
-            .into_iter()
-            .filter_map(|import| match import.original_item {
-                hir::ItemInNs::Macros(mac) => Some((import, mac)),
-                _ => None,
-            })
-            .filter(|&(_, mac)| !ctx.is_item_hidden(&hir::ItemInNs::Macros(mac)))
-            .sorted_by_key(|(import, _)| {
-                compute_fuzzy_completion_order_key(&import.import_path, &user_input_lowercased)
-            })
-            .filter_map(|(import, mac)| {
-                let mut item = CompletionItem::new(
-                    CompletionItemKind::Attribute,
-                    ctx.source_range(),
-                    mac.name(ctx.db)?.to_string(),
-                );
-                item.add_import(ImportEdit { import, scope: import_scope.clone() });
-                if let Some(docs) = mac.docs(ctx.db) {
-                    item.documentation(docs);
-                }
-                Some(item.build())
-            }),
-    );
-    Some(())
-}
-
 struct DeriveDependencies {
     label: &'static str,
     dependencies: &'static [&'static str],
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs
index 05a29dd0ae..18942f8beb 100644
--- a/crates/ide_completion/src/completions/attribute/lint.rs
+++ b/crates/ide_completion/src/completions/attribute/lint.rs
@@ -4,7 +4,7 @@ use syntax::{ast, T};
 
 use crate::{
     context::CompletionContext,
-    item::{CompletionItem, CompletionItemKind},
+    item::{CompletionItem, CompletionItemKind, CompletionKind},
     Completions,
 };
 
@@ -58,9 +58,9 @@ pub(super) fn complete_lint(
             Some(qual) if !is_qualified => format!("{}::{}", qual, name),
             _ => name.to_owned(),
         };
-        let mut item =
-            CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), label);
-        item.documentation(hir::Documentation::new(description.to_owned()));
+        let mut item = CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
+        item.kind(CompletionItemKind::Attribute)
+            .documentation(hir::Documentation::new(description.to_owned()));
         item.add_to(acc)
     }
 }
diff --git a/crates/ide_completion/src/completions/attribute/repr.rs b/crates/ide_completion/src/completions/attribute/repr.rs
index c240912f02..9a12b8571c 100644
--- a/crates/ide_completion/src/completions/attribute/repr.rs
+++ b/crates/ide_completion/src/completions/attribute/repr.rs
@@ -4,7 +4,7 @@ use syntax::ast;
 
 use crate::{
     context::CompletionContext,
-    item::{CompletionItem, CompletionItemKind},
+    item::{CompletionItem, CompletionItemKind, CompletionKind},
     Completions,
 };
 
@@ -30,7 +30,8 @@ pub(super) fn complete_repr(acc: &mut Completions, ctx: &CompletionContext, inpu
             }
 
             let mut item =
-                CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), label);
+                CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
+            item.kind(CompletionItemKind::Attribute);
             if let Some(lookup) = lookup {
                 item.lookup_by(lookup);
             }
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index ce964e986b..213cb70170 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -99,10 +99,13 @@ fn complete_methods(
 mod tests {
     use expect_test::{expect, Expect};
 
-    use crate::tests::{check_edit, completion_list_no_kw};
+    use crate::{
+        tests::{check_edit, filtered_completion_list},
+        CompletionKind,
+    };
 
     fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw(ra_fixture);
+        let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
         expect.assert_eq(&actual);
     }
 
@@ -163,7 +166,7 @@ impl A {
 struct A { the_field: u32 }
 fn foo(a: A) { a.$0() }
 "#,
-            expect![[r#""#]],
+            expect![[""]],
         );
     }
 
@@ -402,7 +405,7 @@ fn foo(a: A) {
    a.$0
 }
 "#,
-            expect![[r#""#]],
+            expect![[""]],
         );
     }
 
@@ -651,7 +654,6 @@ impl Foo { fn foo(&self) { $0 } }"#,
                 lc self       &Foo
                 sp Self
                 st Foo
-                bt u32
                 fd self.field i32
                 me self.foo() fn(&self)
             "#]],
@@ -665,7 +667,6 @@ impl Foo { fn foo(&mut self) { $0 } }"#,
                 lc self       &mut Foo
                 sp Self
                 st Foo
-                bt u32
                 fd self.0     i32
                 me self.foo() fn(&mut self)
             "#]],
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index a5c134714b..d7c8c54315 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -125,12 +125,12 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
         }
     };
 
-    let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone());
+    let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string());
 
     let user_input_lowercased = potential_import_name.to_lowercase();
     let import_assets = import_assets(ctx, potential_import_name)?;
     let import_scope = ImportScope::find_insert_use_container_with_macros(
-        &position_for_import(ctx, Some(import_assets.import_candidate()))?,
+        position_for_import(ctx, Some(import_assets.import_candidate()))?,
         &ctx.sema,
     )?;
 
@@ -158,19 +158,21 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
     Some(())
 }
 
-pub(crate) fn position_for_import(
-    ctx: &CompletionContext,
+pub(crate) fn position_for_import<'a>(
+    ctx: &'a CompletionContext,
     import_candidate: Option<&ImportCandidate>,
-) -> Option<SyntaxNode> {
-    Some(
-        match import_candidate {
-            Some(ImportCandidate::Path(_)) => ctx.name_syntax.as_ref()?.syntax(),
-            Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
-            Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
-            None => return ctx.original_token.parent(),
-        }
-        .clone(),
-    )
+) -> Option<&'a SyntaxNode> {
+    Some(match import_candidate {
+        Some(ImportCandidate::Path(_)) => ctx.name_syntax.as_ref()?.syntax(),
+        Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
+        Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
+        None => ctx
+            .name_syntax
+            .as_ref()
+            .map(|name_ref| name_ref.syntax())
+            .or_else(|| ctx.path_qual().map(|path| path.syntax()))
+            .or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?,
+    })
 }
 
 fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
@@ -203,7 +205,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
     }
 }
 
-pub(crate) fn compute_fuzzy_completion_order_key(
+fn compute_fuzzy_completion_order_key(
     proposed_mod_path: &hir::ModPath,
     user_input_lowercased: &str,
 ) -> usize {
@@ -217,3 +219,1018 @@ pub(crate) fn compute_fuzzy_completion_order_key(
         None => usize::MAX,
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use expect_test::{expect, Expect};
+
+    use crate::{
+        item::CompletionKind,
+        tests::{check_edit, check_edit_with_config, filtered_completion_list, TEST_CONFIG},
+    };
+
+    fn check(ra_fixture: &str, expect: Expect) {
+        let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic);
+        expect.assert_eq(&actual);
+    }
+
+    #[test]
+    fn function_fuzzy_completion() {
+        check_edit(
+            "stdin",
+            r#"
+//- /lib.rs crate:dep
+pub mod io {
+    pub fn stdin() {}
+};
+
+//- /main.rs crate:main deps:dep
+fn main() {
+    stdi$0
+}
+"#,
+            r#"
+use dep::io::stdin;
+
+fn main() {
+    stdin()$0
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn macro_fuzzy_completion() {
+        check_edit(
+            "macro_with_curlies!",
+            r#"
+//- /lib.rs crate:dep
+/// Please call me as macro_with_curlies! {}
+#[macro_export]
+macro_rules! macro_with_curlies {
+    () => {}
+}
+
+//- /main.rs crate:main deps:dep
+fn main() {
+    curli$0
+}
+"#,
+            r#"
+use dep::macro_with_curlies;
+
+fn main() {
+    macro_with_curlies! {$0}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn struct_fuzzy_completion() {
+        check_edit(
+            "ThirdStruct",
+            r#"
+//- /lib.rs crate:dep
+pub struct FirstStruct;
+pub mod some_module {
+    pub struct SecondStruct;
+    pub struct ThirdStruct;
+}
+
+//- /main.rs crate:main deps:dep
+use dep::{FirstStruct, some_module::SecondStruct};
+
+fn main() {
+    this$0
+}
+"#,
+            r#"
+use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
+
+fn main() {
+    ThirdStruct
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn short_paths_are_ignored() {
+        cov_mark::check!(ignore_short_input_for_path);
+
+        check(
+            r#"
+//- /lib.rs crate:dep
+pub struct FirstStruct;
+pub mod some_module {
+    pub struct SecondStruct;
+    pub struct ThirdStruct;
+}
+
+//- /main.rs crate:main deps:dep
+use dep::{FirstStruct, some_module::SecondStruct};
+
+fn main() {
+    t$0
+}
+"#,
+            expect![[r#""#]],
+        );
+    }
+
+    #[test]
+    fn fuzzy_completions_come_in_specific_order() {
+        cov_mark::check!(certain_fuzzy_order_test);
+        check(
+            r#"
+//- /lib.rs crate:dep
+pub struct FirstStruct;
+pub mod some_module {
+    // already imported, omitted
+    pub struct SecondStruct;
+    // does not contain all letters from the query, omitted
+    pub struct UnrelatedOne;
+    // contains all letters from the query, but not in sequence, displayed last
+    pub struct ThiiiiiirdStruct;
+    // contains all letters from the query, but not in the beginning, displayed second
+    pub struct AfterThirdStruct;
+    // contains all letters from the query in the begginning, displayed first
+    pub struct ThirdStruct;
+}
+
+//- /main.rs crate:main deps:dep
+use dep::{FirstStruct, some_module::SecondStruct};
+
+fn main() {
+    hir$0
+}
+"#,
+            expect![[r#"
+                st ThirdStruct (use dep::some_module::ThirdStruct)
+                st AfterThirdStruct (use dep::some_module::AfterThirdStruct)
+                st ThiiiiiirdStruct (use dep::some_module::ThiiiiiirdStruct)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn trait_function_fuzzy_completion() {
+        let fixture = r#"
+        //- /lib.rs crate:dep
+        pub mod test_mod {
+            pub trait TestTrait {
+                const SPECIAL_CONST: u8;
+                type HumbleType;
+                fn weird_function();
+                fn random_method(&self);
+            }
+            pub struct TestStruct {}
+            impl TestTrait for TestStruct {
+                const SPECIAL_CONST: u8 = 42;
+                type HumbleType = ();
+                fn weird_function() {}
+                fn random_method(&self) {}
+            }
+        }
+
+        //- /main.rs crate:main deps:dep
+        fn main() {
+            dep::test_mod::TestStruct::wei$0
+        }
+        "#;
+
+        check(
+            fixture,
+            expect![[r#"
+                fn weird_function() (use dep::test_mod::TestTrait) fn()
+            "#]],
+        );
+
+        check_edit(
+            "weird_function",
+            fixture,
+            r#"
+use dep::test_mod::TestTrait;
+
+fn main() {
+    dep::test_mod::TestStruct::weird_function()$0
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn trait_const_fuzzy_completion() {
+        let fixture = r#"
+        //- /lib.rs crate:dep
+        pub mod test_mod {
+            pub trait TestTrait {
+                const SPECIAL_CONST: u8;
+                type HumbleType;
+                fn weird_function();
+                fn random_method(&self);
+            }
+            pub struct TestStruct {}
+            impl TestTrait for TestStruct {
+                const SPECIAL_CONST: u8 = 42;
+                type HumbleType = ();
+                fn weird_function() {}
+                fn random_method(&self) {}
+            }
+        }
+
+        //- /main.rs crate:main deps:dep
+        fn main() {
+            dep::test_mod::TestStruct::spe$0
+        }
+        "#;
+
+        check(
+            fixture,
+            expect![[r#"
+            ct SPECIAL_CONST (use dep::test_mod::TestTrait)
+        "#]],
+        );
+
+        check_edit(
+            "SPECIAL_CONST",
+            fixture,
+            r#"
+use dep::test_mod::TestTrait;
+
+fn main() {
+    dep::test_mod::TestStruct::SPECIAL_CONST
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn trait_method_fuzzy_completion() {
+        let fixture = r#"
+        //- /lib.rs crate:dep
+        pub mod test_mod {
+            pub trait TestTrait {
+                const SPECIAL_CONST: u8;
+                type HumbleType;
+                fn weird_function();
+                fn random_method(&self);
+            }
+            pub struct TestStruct {}
+            impl TestTrait for TestStruct {
+                const SPECIAL_CONST: u8 = 42;
+                type HumbleType = ();
+                fn weird_function() {}
+                fn random_method(&self) {}
+            }
+        }
+
+        //- /main.rs crate:main deps:dep
+        fn main() {
+            let test_struct = dep::test_mod::TestStruct {};
+            test_struct.ran$0
+        }
+        "#;
+
+        check(
+            fixture,
+            expect![[r#"
+                me random_method() (use dep::test_mod::TestTrait) fn(&self)
+            "#]],
+        );
+
+        check_edit(
+            "random_method",
+            fixture,
+            r#"
+use dep::test_mod::TestTrait;
+
+fn main() {
+    let test_struct = dep::test_mod::TestStruct {};
+    test_struct.random_method()$0
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_trait_type_fuzzy_completion() {
+        check(
+            r#"
+//- /lib.rs crate:dep
+pub mod test_mod {
+    pub trait TestTrait {
+        const SPECIAL_CONST: u8;
+        type HumbleType;
+        fn weird_function();
+        fn random_method(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        const SPECIAL_CONST: u8 = 42;
+        type HumbleType = ();
+        fn weird_function() {}
+        fn random_method(&self) {}
+    }
+}
+
+//- /main.rs crate:main deps:dep
+fn main() {
+    dep::test_mod::TestStruct::hum$0
+}
+"#,
+            expect![[r#""#]],
+        );
+    }
+
+    #[test]
+    fn does_not_propose_names_in_scope() {
+        check(
+            r#"
+//- /lib.rs crate:dep
+pub mod test_mod {
+    pub trait TestTrait {
+        const SPECIAL_CONST: u8;
+        type HumbleType;
+        fn weird_function();
+        fn random_method(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        const SPECIAL_CONST: u8 = 42;
+        type HumbleType = ();
+        fn weird_function() {}
+        fn random_method(&self) {}
+    }
+}
+
+//- /main.rs crate:main deps:dep
+use dep::test_mod::TestStruct;
+fn main() {
+    TestSt$0
+}
+"#,
+            expect![[r#""#]],
+        );
+    }
+
+    #[test]
+    fn does_not_propose_traits_in_scope() {
+        check(
+            r#"
+//- /lib.rs crate:dep
+pub mod test_mod {
+    pub trait TestTrait {
+        const SPECIAL_CONST: u8;
+        type HumbleType;
+        fn weird_function();
+        fn random_method(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        const SPECIAL_CONST: u8 = 42;
+        type HumbleType = ();
+        fn weird_function() {}
+        fn random_method(&self) {}
+    }
+}
+
+//- /main.rs crate:main deps:dep
+use dep::test_mod::{TestStruct, TestTrait};
+fn main() {
+    dep::test_mod::TestStruct::hum$0
+}
+"#,
+            expect![[r#""#]],
+        );
+    }
+
+    #[test]
+    fn blanket_trait_impl_import() {
+        check_edit(
+            "another_function",
+            r#"
+//- /lib.rs crate:dep
+pub mod test_mod {
+    pub struct TestStruct {}
+    pub trait TestTrait {
+        fn another_function();
+    }
+    impl<T> TestTrait for T {
+        fn another_function() {}
+    }
+}
+
+//- /main.rs crate:main deps:dep
+fn main() {
+    dep::test_mod::TestStruct::ano$0
+}
+"#,
+            r#"
+use dep::test_mod::TestTrait;
+
+fn main() {
+    dep::test_mod::TestStruct::another_function()$0
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn zero_input_deprecated_assoc_item_completion() {
+        check(
+            r#"
+//- /lib.rs crate:dep
+pub mod test_mod {
+    #[deprecated]
+    pub trait TestTrait {
+        const SPECIAL_CONST: u8;
+        type HumbleType;
+        fn weird_function();
+        fn random_method(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        const SPECIAL_CONST: u8 = 42;
+        type HumbleType = ();
+        fn weird_function() {}
+        fn random_method(&self) {}
+    }
+}
+
+//- /main.rs crate:main deps:dep
+fn main() {
+    let test_struct = dep::test_mod::TestStruct {};
+    test_struct.$0
+}
+        "#,
+            expect![[r#"
+                me random_method() (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
+            "#]],
+        );
+
+        check(
+            r#"
+//- /lib.rs crate:dep
+pub mod test_mod {
+    #[deprecated]
+    pub trait TestTrait {
+        const SPECIAL_CONST: u8;
+        type HumbleType;
+        fn weird_function();
+        fn random_method(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        const SPECIAL_CONST: u8 = 42;
+        type HumbleType = ();
+        fn weird_function() {}
+        fn random_method(&self) {}
+    }
+}
+
+//- /main.rs crate:main deps:dep
+fn main() {
+    dep::test_mod::TestStruct::$0
+}
+"#,
+            expect![[r#"
+                fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
+                ct SPECIAL_CONST (use dep::test_mod::TestTrait) DEPRECATED
+            "#]],
+        );
+    }
+
+    #[test]
+    fn no_completions_in_use_statements() {
+        check(
+            r#"
+//- /lib.rs crate:dep
+pub mod io {
+    pub fn stdin() {}
+};
+
+//- /main.rs crate:main deps:dep
+use stdi$0
+
+fn main() {}
+"#,
+            expect![[]],
+        );
+    }
+
+    #[test]
+    fn prefix_config_usage() {
+        let fixture = r#"
+mod foo {
+    pub mod bar {
+        pub struct Item;
+    }
+}
+
+use crate::foo::bar;
+
+fn main() {
+    Ite$0
+}"#;
+        let mut config = TEST_CONFIG;
+
+        config.insert_use.prefix_kind = hir::PrefixKind::ByCrate;
+        check_edit_with_config(
+            config.clone(),
+            "Item",
+            fixture,
+            r#"
+mod foo {
+    pub mod bar {
+        pub struct Item;
+    }
+}
+
+use crate::foo::bar::{self, Item};
+
+fn main() {
+    Item
+}"#,
+        );
+
+        config.insert_use.prefix_kind = hir::PrefixKind::BySelf;
+        check_edit_with_config(
+            config.clone(),
+            "Item",
+            fixture,
+            r#"
+mod foo {
+    pub mod bar {
+        pub struct Item;
+    }
+}
+
+use crate::foo::bar;
+
+use self::foo::bar::Item;
+
+fn main() {
+    Item
+}"#,
+        );
+
+        config.insert_use.prefix_kind = hir::PrefixKind::Plain;
+        check_edit_with_config(
+            config,
+            "Item",
+            fixture,
+            r#"
+mod foo {
+    pub mod bar {
+        pub struct Item;
+    }
+}
+
+use foo::bar::Item;
+
+use crate::foo::bar;
+
+fn main() {
+    Item
+}"#,
+        );
+    }
+
+    #[test]
+    fn unresolved_qualifier() {
+        let fixture = r#"
+mod foo {
+    pub mod bar {
+        pub mod baz {
+            pub struct Item;
+        }
+    }
+}
+
+fn main() {
+    bar::baz::Ite$0
+}"#;
+
+        check(
+            fixture,
+            expect![[r#"
+        st Item (use foo::bar::baz::Item)
+        "#]],
+        );
+
+        check_edit(
+            "Item",
+            fixture,
+            r#"
+        use foo::bar;
+
+        mod foo {
+            pub mod bar {
+                pub mod baz {
+                    pub struct Item;
+                }
+            }
+        }
+
+        fn main() {
+            bar::baz::Item
+        }"#,
+        );
+    }
+
+    #[test]
+    fn unresolved_assoc_item_container() {
+        let fixture = r#"
+mod foo {
+    pub struct Item;
+
+    impl Item {
+        pub const TEST_ASSOC: usize = 3;
+    }
+}
+
+fn main() {
+    Item::TEST_A$0
+}"#;
+
+        check(
+            fixture,
+            expect![[r#"
+        ct TEST_ASSOC (use foo::Item)
+        "#]],
+        );
+
+        check_edit(
+            "TEST_ASSOC",
+            fixture,
+            r#"
+use foo::Item;
+
+mod foo {
+    pub struct Item;
+
+    impl Item {
+        pub const TEST_ASSOC: usize = 3;
+    }
+}
+
+fn main() {
+    Item::TEST_ASSOC
+}"#,
+        );
+    }
+
+    #[test]
+    fn unresolved_assoc_item_container_with_path() {
+        let fixture = r#"
+mod foo {
+    pub mod bar {
+        pub struct Item;
+
+        impl Item {
+            pub const TEST_ASSOC: usize = 3;
+        }
+    }
+}
+
+fn main() {
+    bar::Item::TEST_A$0
+}"#;
+
+        check(
+            fixture,
+            expect![[r#"
+        ct TEST_ASSOC (use foo::bar::Item)
+    "#]],
+        );
+
+        check_edit(
+            "TEST_ASSOC",
+            fixture,
+            r#"
+use foo::bar;
+
+mod foo {
+    pub mod bar {
+        pub struct Item;
+
+        impl Item {
+            pub const TEST_ASSOC: usize = 3;
+        }
+    }
+}
+
+fn main() {
+    bar::Item::TEST_ASSOC
+}"#,
+        );
+    }
+
+    #[test]
+    fn fuzzy_unresolved_path() {
+        check(
+            r#"
+mod foo {
+    pub mod bar {
+        pub struct Item;
+
+        impl Item {
+            pub const TEST_ASSOC: usize = 3;
+        }
+    }
+}
+
+fn main() {
+    bar::ASS$0
+}"#,
+            expect![[]],
+        )
+    }
+
+    #[test]
+    fn unqualified_assoc_items_are_omitted() {
+        check(
+            r#"
+mod something {
+    pub trait BaseTrait {
+        fn test_function() -> i32;
+    }
+
+    pub struct Item1;
+    pub struct Item2;
+
+    impl BaseTrait for Item1 {
+        fn test_function() -> i32 {
+            1
+        }
+    }
+
+    impl BaseTrait for Item2 {
+        fn test_function() -> i32 {
+            2
+        }
+    }
+}
+
+fn main() {
+    test_f$0
+}"#,
+            expect![[]],
+        )
+    }
+
+    #[test]
+    fn case_matters() {
+        check(
+            r#"
+mod foo {
+    pub const TEST_CONST: usize = 3;
+    pub fn test_function() -> i32 {
+        4
+    }
+}
+
+fn main() {
+    TE$0
+}"#,
+            expect![[r#"
+        ct TEST_CONST (use foo::TEST_CONST)
+    "#]],
+        );
+
+        check(
+            r#"
+mod foo {
+    pub const TEST_CONST: usize = 3;
+    pub fn test_function() -> i32 {
+        4
+    }
+}
+
+fn main() {
+    te$0
+}"#,
+            expect![[r#"
+        ct TEST_CONST (use foo::TEST_CONST)
+        fn test_function() (use foo::test_function) fn() -> i32
+    "#]],
+        );
+
+        check(
+            r#"
+mod foo {
+    pub const TEST_CONST: usize = 3;
+    pub fn test_function() -> i32 {
+        4
+    }
+}
+
+fn main() {
+    Te$0
+}"#,
+            expect![[]],
+        );
+    }
+
+    #[test]
+    fn no_fuzzy_during_fields_of_record_lit_syntax() {
+        check(
+            r#"
+mod m {
+    pub fn some_fn() -> i32 {
+        42
+    }
+}
+struct Foo {
+    some_field: i32,
+}
+fn main() {
+    let _ = Foo { so$0 };
+}
+"#,
+            expect![[]],
+        );
+    }
+
+    #[test]
+    fn fuzzy_after_fields_of_record_lit_syntax() {
+        check(
+            r#"
+mod m {
+    pub fn some_fn() -> i32 {
+        42
+    }
+}
+struct Foo {
+    some_field: i32,
+}
+fn main() {
+    let _ = Foo { some_field: so$0 };
+}
+"#,
+            expect![[r#"
+                fn some_fn() (use m::some_fn) fn() -> i32
+            "#]],
+        );
+    }
+
+    #[test]
+    fn no_flyimports_in_traits_and_impl_declarations() {
+        check(
+            r#"
+mod m {
+    pub fn some_fn() -> i32 {
+        42
+    }
+}
+trait Foo {
+    som$0
+}
+"#,
+            expect![[r#""#]],
+        );
+
+        check(
+            r#"
+mod m {
+    pub fn some_fn() -> i32 {
+        42
+    }
+}
+struct Foo;
+impl Foo {
+    som$0
+}
+"#,
+            expect![[r#""#]],
+        );
+
+        check(
+            r#"
+mod m {
+    pub fn some_fn() -> i32 {
+        42
+    }
+}
+struct Foo;
+trait Bar {}
+impl Bar for Foo {
+    som$0
+}
+"#,
+            expect![[r#""#]],
+        );
+    }
+
+    #[test]
+    fn no_inherent_candidates_proposed() {
+        check(
+            r#"
+mod baz {
+    pub trait DefDatabase {
+        fn method1(&self);
+    }
+    pub trait HirDatabase: DefDatabase {
+        fn method2(&self);
+    }
+}
+
+mod bar {
+    fn test(db: &dyn crate::baz::HirDatabase) {
+        db.metho$0
+    }
+}
+            "#,
+            expect![[r#""#]],
+        );
+    }
+
+    #[test]
+    fn respects_doc_hidden() {
+        check(
+            r#"
+//- /lib.rs crate:lib deps:dep
+fn f() {
+    ().fro$0
+}
+
+//- /dep.rs crate:dep
+#[doc(hidden)]
+pub trait Private {
+    fn frob(&self) {}
+}
+
+impl<T> Private for T {}
+            "#,
+            expect![[r#""#]],
+        );
+        check(
+            r#"
+//- /lib.rs crate:lib deps:dep
+fn f() {
+    ().fro$0
+}
+
+//- /dep.rs crate:dep
+pub trait Private {
+    #[doc(hidden)]
+    fn frob(&self) {}
+}
+
+impl<T> Private for T {}
+            "#,
+            expect![[r#""#]],
+        );
+    }
+
+    #[test]
+    fn regression_9760() {
+        check(
+            r#"
+struct Struct;
+fn main() {}
+
+mod mud {
+    fn func() {
+        let struct_instance = Stru$0
+    }
+}
+"#,
+            expect![[r#"
+                st Struct (use crate::Struct)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn flyimport_pattern() {
+        check(
+            r#"
+mod module {
+    pub struct Struct;
+}
+fn function() {
+    let Str$0
+}
+"#,
+            expect![[r#"
+                st Struct (use module::Struct)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn flyimport_rename() {
+        check(
+            r#"
+mod module {
+    pub struct Struct;
+}
+use self as Str$0;
+    "#,
+            expect![[r#""#]],
+        );
+    }
+}
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index e910c1daaa..a9f1944e28 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -8,7 +8,7 @@ use syntax::{
 
 use crate::{
     context::{ParamKind, PatternContext},
-    CompletionContext, CompletionItem, CompletionItemKind, Completions,
+    CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
 };
 
 /// Complete repeated parameters, both name and type. For example, if all
@@ -75,7 +75,7 @@ fn add_new_item_to_acc(
     label: String,
     lookup: String,
 ) {
-    let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label);
-    item.lookup_by(lookup);
+    let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label);
+    item.kind(CompletionItemKind::Binding).lookup_by(lookup);
     item.add_to(acc)
 }
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index afb8df2911..31aabd98d3 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -6,7 +6,7 @@ use syntax::{SyntaxKind, T};
 
 use crate::{
     context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, CompletionItem,
-    CompletionItemKind, Completions,
+    CompletionItemKind, CompletionKind, Completions,
 };
 
 pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
@@ -158,7 +158,8 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
 }
 
 fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
-    let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
+    let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw);
+    item.kind(CompletionItemKind::Keyword);
 
     match ctx.config.snippet_cap {
         Some(cap) => {
@@ -180,15 +181,115 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet
 mod tests {
     use expect_test::{expect, Expect};
 
-    use crate::tests::{check_edit, completion_list};
+    use crate::{
+        tests::{check_edit, filtered_completion_list},
+        CompletionKind,
+    };
 
     fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list(ra_fixture);
+        let actual = filtered_completion_list(ra_fixture, CompletionKind::Keyword);
         expect.assert_eq(&actual)
     }
 
     #[test]
-    fn test_else_edit_after_if() {
+    fn test_keywords_in_function() {
+        check(
+            r"fn quux() { $0 }",
+            expect![[r#"
+                kw unsafe
+                kw fn
+                kw const
+                kw type
+                kw impl
+                kw extern
+                kw use
+                kw trait
+                kw static
+                kw mod
+                kw match
+                kw while
+                kw while let
+                kw loop
+                kw if
+                kw if let
+                kw for
+                kw true
+                kw false
+                kw let
+                kw return
+                kw self
+                kw super
+                kw crate
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_keywords_inside_block() {
+        check(
+            r"fn quux() { if true { $0 } }",
+            expect![[r#"
+                kw unsafe
+                kw fn
+                kw const
+                kw type
+                kw impl
+                kw extern
+                kw use
+                kw trait
+                kw static
+                kw mod
+                kw match
+                kw while
+                kw while let
+                kw loop
+                kw if
+                kw if let
+                kw for
+                kw true
+                kw false
+                kw let
+                kw return
+                kw self
+                kw super
+                kw crate
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_keywords_after_if() {
+        check(
+            r#"fn quux() { if true { () } $0 }"#,
+            expect![[r#"
+                kw unsafe
+                kw fn
+                kw const
+                kw type
+                kw impl
+                kw extern
+                kw use
+                kw trait
+                kw static
+                kw mod
+                kw match
+                kw while
+                kw while let
+                kw loop
+                kw if
+                kw if let
+                kw for
+                kw true
+                kw false
+                kw let
+                kw else
+                kw else if
+                kw return
+                kw self
+                kw super
+                kw crate
+            "#]],
+        );
         check_edit(
             "else",
             r#"fn quux() { if true { () } $0 }"#,
@@ -198,6 +299,68 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_keywords_in_match_arm() {
+        check(
+            r#"
+fn quux() -> i32 {
+    match () { () => $0 }
+}
+"#,
+            expect![[r#"
+                kw unsafe
+                kw match
+                kw while
+                kw while let
+                kw loop
+                kw if
+                kw if let
+                kw for
+                kw true
+                kw false
+                kw return
+                kw self
+                kw super
+                kw crate
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_keywords_in_loop() {
+        check(
+            r"fn my() { loop { $0 } }",
+            expect![[r#"
+                kw unsafe
+                kw fn
+                kw const
+                kw type
+                kw impl
+                kw extern
+                kw use
+                kw trait
+                kw static
+                kw mod
+                kw match
+                kw while
+                kw while let
+                kw loop
+                kw if
+                kw if let
+                kw for
+                kw true
+                kw false
+                kw let
+                kw continue
+                kw break
+                kw return
+                kw self
+                kw super
+                kw crate
+            "#]],
+        );
+    }
+
     #[test]
     fn test_keywords_after_unsafe_in_block_expr() {
         check(
@@ -206,12 +369,38 @@ mod tests {
                 kw fn
                 kw trait
                 kw impl
-                sn pd
-                sn ppd
             "#]],
         );
     }
 
+    #[test]
+    fn no_keyword_completion_in_comments() {
+        cov_mark::check!(no_keyword_completion_in_comments);
+        check(
+            r#"
+fn test() {
+    let x = 2; // A comment$0
+}
+"#,
+            expect![[""]],
+        );
+        check(
+            r#"
+/*
+Some multi-line comment$0
+*/
+"#,
+            expect![[""]],
+        );
+        check(
+            r#"
+/// Some doc comment
+/// let test$0 = 1
+"#,
+            expect![[""]],
+        );
+    }
+
     #[test]
     fn test_completion_await_impls_future() {
         check(
@@ -224,18 +413,6 @@ fn foo(a: A) { a.$0 }
 "#,
             expect![[r#"
                 kw await expr.await
-                sn ref   &expr
-                sn refm  &mut expr
-                sn match match expr {}
-                sn box   Box::new(expr)
-                sn ok    Ok(expr)
-                sn err   Err(expr)
-                sn some  Some(expr)
-                sn dbg   dbg!(expr)
-                sn dbgr  dbg!(&expr)
-                sn call  function(expr)
-                sn let   let
-                sn letm  let mut
             "#]],
         );
 
@@ -250,22 +427,83 @@ fn foo() {
 "#,
             expect![[r#"
                 kw await expr.await
-                sn ref   &expr
-                sn refm  &mut expr
-                sn match match expr {}
-                sn box   Box::new(expr)
-                sn ok    Ok(expr)
-                sn err   Err(expr)
-                sn some  Some(expr)
-                sn dbg   dbg!(expr)
-                sn dbgr  dbg!(&expr)
-                sn call  function(expr)
-                sn let   let
-                sn letm  let mut
             "#]],
         )
     }
 
+    #[test]
+    fn after_let() {
+        check(
+            r#"fn main() { let _ = $0 }"#,
+            expect![[r#"
+                kw unsafe
+                kw match
+                kw while
+                kw while let
+                kw loop
+                kw if
+                kw if let
+                kw for
+                kw true
+                kw false
+                kw return
+                kw self
+                kw super
+                kw crate
+            "#]],
+        )
+    }
+
+    #[test]
+    fn skip_struct_initializer() {
+        cov_mark::check!(no_keyword_completion_in_record_lit);
+        check(
+            r#"
+struct Foo {
+    pub f: i32,
+}
+fn foo() {
+    Foo {
+        $0
+    }
+}
+"#,
+            expect![[r#""#]],
+        );
+    }
+
+    #[test]
+    fn struct_initializer_field_expr() {
+        check(
+            r#"
+struct Foo {
+    pub f: i32,
+}
+fn foo() {
+    Foo {
+        f: $0
+    }
+}
+"#,
+            expect![[r#"
+                kw unsafe
+                kw match
+                kw while
+                kw while let
+                kw loop
+                kw if
+                kw if let
+                kw for
+                kw true
+                kw false
+                kw return
+                kw self
+                kw super
+                kw crate
+            "#]],
+        );
+    }
+
     #[test]
     fn let_semi() {
         cov_mark::check!(let_semi);
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs
index 28be83f196..1c864c0e70 100644
--- a/crates/ide_completion/src/completions/mod_.rs
+++ b/crates/ide_completion/src/completions/mod_.rs
@@ -11,7 +11,7 @@ use rustc_hash::FxHashSet;
 
 use crate::{patterns::ImmediateLocation, CompletionItem};
 
-use crate::{context::CompletionContext, Completions};
+use crate::{context::CompletionContext, item::CompletionKind, Completions};
 
 /// Complete mod declaration, i.e. `mod $0 ;`
 pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@@ -80,7 +80,8 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
             if mod_under_caret.semicolon_token().is_none() {
                 label.push(';');
             }
-            let item = CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label);
+            let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label);
+            item.kind(SymbolKind::Module);
             item.add_to(acc)
         });
 
@@ -140,9 +141,8 @@ fn module_chain_to_containing_module_file(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
-
     use crate::tests::completion_list;
+    use expect_test::{expect, Expect};
 
     fn check(ra_fixture: &str, expect: Expect) {
         let actual = completion_list(ra_fixture);
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 4ee257ab43..4ace346768 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -15,9 +15,11 @@ use syntax::{
 use text_edit::TextEdit;
 
 use crate::{
-    completions::postfix::format_like::add_format_like_completions, context::CompletionContext,
-    item::Builder, patterns::ImmediateLocation, CompletionItem, CompletionItemKind,
-    CompletionRelevance, Completions, SnippetScope,
+    completions::postfix::format_like::add_format_like_completions,
+    context::CompletionContext,
+    item::{Builder, CompletionKind},
+    patterns::ImmediateLocation,
+    CompletionItem, CompletionItemKind, CompletionRelevance, Completions, SnippetScope,
 };
 
 pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
@@ -43,9 +45,8 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
 
     // Suggest .await syntax for types that implement Future trait
     if receiver_ty.impls_future(ctx.db) {
-        let mut item =
-            CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await");
-        item.detail("expr.await");
+        let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await");
+        item.kind(CompletionItemKind::Keyword).detail("expr.await");
         item.add_to(acc);
     }
 
@@ -223,9 +224,8 @@ fn build_postfix_snippet_builder<'ctx>(
     ) -> impl Fn(&str, &str, &str) -> Builder + 'ctx {
         move |label, detail, snippet| {
             let edit = TextEdit::replace(delete_range, snippet.to_string());
-            let mut item =
-                CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
-            item.detail(detail).snippet_edit(cap, edit);
+            let mut item = CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label);
+            item.detail(detail).kind(CompletionItemKind::Snippet).snippet_edit(cap, edit);
             if ctx.original_token.text() == label {
                 let relevance =
                     CompletionRelevance { exact_postfix_snippet_match: true, ..Default::default() };
@@ -270,12 +270,12 @@ mod tests {
     use expect_test::{expect, Expect};
 
     use crate::{
-        tests::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG},
-        CompletionConfig, Snippet,
+        tests::{check_edit, check_edit_with_config, filtered_completion_list, TEST_CONFIG},
+        CompletionConfig, CompletionKind, Snippet,
     };
 
     fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list(ra_fixture);
+        let actual = filtered_completion_list(ra_fixture, CompletionKind::Postfix);
         expect.assert_eq(&actual)
     }
 
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index e9d39edc43..f61baf184b 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -250,10 +250,13 @@ fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enu
 mod tests {
     use expect_test::{expect, Expect};
 
-    use crate::tests::{check_edit, completion_list_no_kw};
+    use crate::{
+        tests::{check_edit, filtered_completion_list},
+        CompletionKind,
+    };
 
     fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw(ra_fixture);
+        let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
         expect.assert_eq(&actual);
     }
 
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs
index f0c81f66bc..80132c2566 100644
--- a/crates/ide_completion/src/completions/record.rs
+++ b/crates/ide_completion/src/completions/record.rs
@@ -3,7 +3,8 @@ use ide_db::{helpers::FamousDefs, SymbolKind};
 use syntax::{ast::Expr, T};
 
 use crate::{
-    patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, Completions,
+    item::CompletionKind, patterns::ImmediateLocation, CompletionContext, CompletionItem,
+    CompletionItemKind, Completions,
 };
 
 pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@@ -21,17 +22,20 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
             let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
             if impl_default_trait && !missing_fields.is_empty() && ctx.path_qual().is_none() {
                 let completion_text = "..Default::default()";
-                let mut item =
-                    CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
+                let mut item = CompletionItem::new(
+                    CompletionKind::Snippet,
+                    ctx.source_range(),
+                    completion_text,
+                );
                 let completion_text =
                     completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
-                item.insert_text(completion_text);
+                item.insert_text(completion_text).kind(SymbolKind::Field);
                 item.add_to(acc);
             }
             if ctx.previous_token_is(T![.]) {
                 let mut item =
-                    CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), "..");
-                item.insert_text(".");
+                    CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), "..");
+                item.insert_text(".").kind(CompletionItemKind::Snippet);
                 item.add_to(acc);
                 return None;
             }
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index 1840e780ed..a0e5f56129 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -6,12 +6,12 @@ use syntax::T;
 
 use crate::{
     context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem,
-    CompletionItemKind, Completions, SnippetScope,
+    CompletionItemKind, CompletionKind, Completions, SnippetScope,
 };
 
 fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
-    let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
-    item.insert_snippet(cap, snippet);
+    let mut item = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), label);
+    item.insert_snippet(cap, snippet).kind(CompletionItemKind::Snippet);
     item
 }
 
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs
index fc6ef5839c..31accd035f 100644
--- a/crates/ide_completion/src/completions/trait_impl.rs
+++ b/crates/ide_completion/src/completions/trait_impl.rs
@@ -40,7 +40,7 @@ use syntax::{
 };
 use text_edit::TextEdit;
 
-use crate::{CompletionContext, CompletionItem, CompletionItemKind, Completions};
+use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
 
 #[derive(Debug, PartialEq, Eq)]
 enum ImplCompletionKind {
@@ -141,14 +141,14 @@ fn add_function_impl(
         format!("fn {}(..)", fn_name)
     };
 
+    let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label);
+    item.lookup_by(fn_name).set_documentation(func.docs(ctx.db));
+
     let completion_kind = if func.self_param(ctx.db).is_some() {
         CompletionItemKind::Method
     } else {
         CompletionItemKind::SymbolKind(SymbolKind::Function)
     };
-    let mut item = CompletionItem::new(completion_kind, ctx.source_range(), label);
-    item.lookup_by(fn_name).set_documentation(func.docs(ctx.db));
-
     let range = replacement_range(ctx, fn_def_node);
 
     if let Some(source) = func.source(ctx.db) {
@@ -170,6 +170,7 @@ fn add_function_impl(
                     item.text_edit(TextEdit::replace(range, header));
                 }
             };
+            item.kind(completion_kind);
             item.add_to(acc);
         }
     }
@@ -210,9 +211,10 @@ fn add_type_alias_impl(
     let snippet = format!("type {} = ", alias_name);
 
     let range = replacement_range(ctx, type_def_node);
-    let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), snippet.clone());
+    let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
     item.text_edit(TextEdit::replace(range, snippet))
         .lookup_by(alias_name)
+        .kind(SymbolKind::TypeAlias)
         .set_documentation(type_alias.docs(ctx.db));
     item.add_to(acc);
 }
@@ -239,9 +241,10 @@ fn add_const_impl(
 
                 let range = replacement_range(ctx, const_def_node);
                 let mut item =
-                    CompletionItem::new(SymbolKind::Const, ctx.source_range(), snippet.clone());
+                    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
                 item.text_edit(TextEdit::replace(range, snippet))
                     .lookup_by(const_name)
+                    .kind(SymbolKind::Const)
                     .set_documentation(const_.docs(ctx.db));
                 item.add_to(acc);
             }
@@ -287,10 +290,13 @@ fn replacement_range(ctx: &CompletionContext, item: &SyntaxNode) -> TextRange {
 mod tests {
     use expect_test::{expect, Expect};
 
-    use crate::tests::{check_edit, completion_list_no_kw};
+    use crate::{
+        tests::{check_edit, filtered_completion_list},
+        CompletionKind,
+    };
 
     fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw(ra_fixture);
+        let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic);
         expect.assert_eq(&actual)
     }
 
@@ -307,12 +313,7 @@ impl Test for T {
     }
 }
 ",
-            expect![[r#"
-                sp Self
-                tt Test
-                st T
-                bt u32
-            "#]],
+            expect![[""]],
         );
 
         check(
@@ -355,7 +356,7 @@ impl Test for T {
     }
 }
 ",
-            expect![[r#""#]],
+            expect![[""]],
         );
 
         check(
@@ -367,10 +368,7 @@ impl Test for T {
     fn test(t$0)
 }
 ",
-            expect![[r#"
-                sp Self
-                st T
-            "#]],
+            expect![[""]],
         );
 
         check(
@@ -382,10 +380,7 @@ impl Test for T {
     fn test(f: fn $0)
 }
 ",
-            expect![[r#"
-                sp Self
-                st T
-            "#]],
+            expect![[""]],
         );
     }
 
@@ -400,7 +395,7 @@ impl Test for T {
     const TEST: fn $0
 }
 ",
-            expect![[r#""#]],
+            expect![[""]],
         );
 
         check(
@@ -412,12 +407,7 @@ impl Test for T {
     const TEST: T$0
 }
 ",
-            expect![[r#"
-                sp Self
-                tt Test
-                st T
-                bt u32
-            "#]],
+            expect![[""]],
         );
 
         check(
@@ -429,12 +419,7 @@ impl Test for T {
     const TEST: u32 = f$0
 }
 ",
-            expect![[r#"
-                sp Self
-                tt Test
-                st T
-                bt u32
-            "#]],
+            expect![[""]],
         );
 
         check(
@@ -448,12 +433,7 @@ impl Test for T {
     };
 }
 ",
-            expect![[r#"
-                sp Self
-                tt Test
-                st T
-                bt u32
-            "#]],
+            expect![[""]],
         );
 
         check(
@@ -496,12 +476,7 @@ impl Test for T {
     type Test = T$0;
 }
 ",
-            expect![[r#"
-                sp Self
-                tt Test
-                st T
-                bt u32
-            "#]],
+            expect![[""]],
         );
 
         check(
@@ -513,12 +488,7 @@ impl Test for T {
     type Test = fn $0;
 }
 ",
-            expect![[r#"
-                sp Self
-                tt Test
-                st T
-                bt u32
-            "#]],
+            expect![[""]],
         );
     }
 
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 825fae587b..afacf7fe03 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -117,15 +117,24 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
 mod tests {
     use expect_test::{expect, Expect};
 
-    use crate::tests::{check_edit, completion_list_no_kw};
+    use crate::{
+        tests::{check_edit, filtered_completion_list_with_config, TEST_CONFIG},
+        CompletionConfig, CompletionKind,
+    };
 
     fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw(ra_fixture);
+        check_with_config(TEST_CONFIG, ra_fixture, expect);
+    }
+
+    fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
+        let actual =
+            filtered_completion_list_with_config(config, ra_fixture, CompletionKind::Reference);
         expect.assert_eq(&actual)
     }
 
     #[test]
     fn completes_if_prefix_is_keyword() {
+        cov_mark::check!(completes_if_prefix_is_keyword);
         check_edit(
             "wherewolf",
             r#"
@@ -179,7 +188,6 @@ pub mod prelude {
 "#,
             expect![[r#"
                 md std
-                bt u32
                 st Option
             "#]],
         );
@@ -209,7 +217,6 @@ mod macros {
                 fn f()        fn()
                 ma concat!(…) #[macro_export] macro_rules! concat
                 md std
-                bt u32
             "##]],
         );
     }
@@ -238,7 +245,6 @@ pub mod prelude {
             expect![[r#"
                 md std
                 md core
-                bt u32
                 st String
             "#]],
         );
@@ -267,7 +273,6 @@ pub mod prelude {
             expect![[r#"
                 fn f() fn()
                 md std
-                bt u32
             "#]],
         );
     }
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 0cb484d507..4e3abff3b3 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -134,6 +134,7 @@ impl<'a> CompletionContext<'a> {
         // check kind of macro-expanded token, but use range of original token
         let kind = self.token.kind();
         if kind == IDENT || kind == LIFETIME_IDENT || kind == UNDERSCORE || kind.is_keyword() {
+            cov_mark::hit!(completes_if_prefix_is_keyword);
             self.original_token.text_range()
         } else if kind == CHAR {
             // assume we are completing a lifetime but the user has only typed the '
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 3f0accfbe1..a9eec472ca 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -21,6 +21,10 @@ use text_edit::TextEdit;
 /// `CompletionItem`, use `new` method and the `Builder` struct.
 #[derive(Clone)]
 pub struct CompletionItem {
+    /// Used only internally in tests, to check only specific kind of
+    /// completion (postfix, keyword, reference, etc).
+    #[allow(unused)]
+    pub(crate) completion_kind: CompletionKind,
     /// Label in the completion pop up which identifies completion.
     label: String,
     /// Range of identifier that is being completed.
@@ -39,7 +43,7 @@ pub struct CompletionItem {
     is_snippet: bool,
 
     /// What item (struct, function, etc) are we completing.
-    kind: CompletionItemKind,
+    kind: Option<CompletionItemKind>,
 
     /// Lookup is used to check if completion item indeed can complete current
     /// ident.
@@ -88,7 +92,9 @@ impl fmt::Debug for CompletionItem {
         } else {
             s.field("text_edit", &self.text_edit);
         }
-        s.field("kind", &self.kind());
+        if let Some(kind) = self.kind().as_ref() {
+            s.field("kind", kind);
+        }
         if self.lookup() != self.label() {
             s.field("lookup", &self.lookup());
         }
@@ -264,15 +270,32 @@ impl CompletionItemKind {
     }
 }
 
+// FIXME remove this?
+/// Like [`CompletionItemKind`] but solely used for filtering test results.
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+pub(crate) enum CompletionKind {
+    /// Parser-based keyword completion.
+    Keyword,
+    /// Your usual "complete all valid identifiers".
+    Reference,
+    /// "Secret sauce" completions.
+    Magic,
+    Snippet,
+    Postfix,
+    BuiltinType,
+    Attribute,
+}
+
 impl CompletionItem {
     pub(crate) fn new(
-        kind: impl Into<CompletionItemKind>,
+        completion_kind: CompletionKind,
         source_range: TextRange,
         label: impl Into<String>,
     ) -> Builder {
         let label = label.into();
         Builder {
             source_range,
+            completion_kind,
             label,
             insert_text: None,
             is_snippet: false,
@@ -280,7 +303,7 @@ impl CompletionItem {
             detail: None,
             documentation: None,
             lookup: None,
-            kind: kind.into(),
+            kind: None,
             text_edit: None,
             deprecated: false,
             trigger_call_info: None,
@@ -319,7 +342,7 @@ impl CompletionItem {
         self.lookup.as_deref().unwrap_or(&self.label)
     }
 
-    pub fn kind(&self) -> CompletionItemKind {
+    pub fn kind(&self) -> Option<CompletionItemKind> {
         self.kind
     }
 
@@ -378,6 +401,7 @@ impl ImportEdit {
 #[derive(Clone)]
 pub(crate) struct Builder {
     source_range: TextRange,
+    completion_kind: CompletionKind,
     imports_to_add: SmallVec<[ImportEdit; 1]>,
     trait_name: Option<String>,
     label: String,
@@ -386,7 +410,7 @@ pub(crate) struct Builder {
     detail: Option<String>,
     documentation: Option<Documentation>,
     lookup: Option<String>,
-    kind: CompletionItemKind,
+    kind: Option<CompletionItemKind>,
     text_edit: Option<TextEdit>,
     deprecated: bool,
     trigger_call_info: Option<bool>,
@@ -430,6 +454,7 @@ impl Builder {
             documentation: self.documentation,
             lookup,
             kind: self.kind,
+            completion_kind: self.completion_kind,
             deprecated: self.deprecated,
             trigger_call_info: self.trigger_call_info.unwrap_or(false),
             relevance: self.relevance,
@@ -462,6 +487,10 @@ impl Builder {
         self.is_snippet = true;
         self.insert_text(snippet)
     }
+    pub(crate) fn kind(&mut self, kind: impl Into<CompletionItemKind>) -> &mut Builder {
+        self.kind = Some(kind.into());
+        self
+    }
     pub(crate) fn text_edit(&mut self, edit: TextEdit) -> &mut Builder {
         self.text_edit = Some(edit);
         self
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 463744f22a..6680e66c60 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -24,7 +24,7 @@ use ide_db::{
 use syntax::algo;
 use text_edit::TextEdit;
 
-use crate::{completions::Completions, context::CompletionContext};
+use crate::{completions::Completions, context::CompletionContext, item::CompletionKind};
 
 pub use crate::{
     config::CompletionConfig,
@@ -182,7 +182,7 @@ pub fn resolve_completion_edits(
 ) -> Option<Vec<TextEdit>> {
     let _p = profile::span("resolve_completion_edits");
     let ctx = CompletionContext::new(db, position, config)?;
-    let position_for_import = &position_for_import(&ctx, None)?;
+    let position_for_import = position_for_import(&ctx, None)?;
     let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?;
 
     let current_module = ctx.sema.scope(position_for_import).module()?;
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 4180d704a3..58443f566e 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -22,7 +22,7 @@ use crate::{
     context::{PathCompletionContext, PathKind},
     item::{CompletionRelevanceTypeMatch, ImportEdit},
     render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
-    CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
+    CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
 };
 /// Interface for data and methods required for items rendering.
 #[derive(Debug)]
@@ -85,7 +85,7 @@ pub(crate) fn render_field(
     let is_deprecated = ctx.is_deprecated(field);
     let name = field.name(ctx.db()).to_string();
     let mut item = CompletionItem::new(
-        SymbolKind::Field,
+        CompletionKind::Reference,
         ctx.source_range(),
         receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
     );
@@ -94,7 +94,8 @@ pub(crate) fn render_field(
         exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
         ..CompletionRelevance::default()
     });
-    item.detail(ty.display(ctx.db()).to_string())
+    item.kind(SymbolKind::Field)
+        .detail(ty.display(ctx.db()).to_string())
         .set_documentation(field.docs(ctx.db()))
         .set_deprecated(is_deprecated)
         .lookup_by(name.as_str());
@@ -117,11 +118,13 @@ pub(crate) fn render_tuple_field(
     ty: &hir::Type,
 ) -> CompletionItem {
     let mut item = CompletionItem::new(
-        SymbolKind::Field,
+        CompletionKind::Reference,
         ctx.source_range(),
         receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
     );
-    item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string());
+    item.kind(SymbolKind::Field)
+        .detail(ty.display(ctx.db()).to_string())
+        .lookup_by(field.to_string());
     item.build()
 }
 
@@ -144,7 +147,10 @@ pub(crate) fn render_resolution_with_import(
         hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
         _ => item_name(ctx.db(), import_edit.import.original_item)?,
     };
-    render_resolution_(ctx, local_name, Some(import_edit), &resolution)
+    render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| {
+        item.completion_kind = CompletionKind::Magic;
+        item
+    })
 }
 
 fn render_resolution_(
@@ -156,6 +162,11 @@ fn render_resolution_(
     let _p = profile::span("render_resolution");
     use hir::ModuleDef::*;
 
+    let completion_kind = match resolution {
+        hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
+        _ => CompletionKind::Reference,
+    };
+
     let kind = match resolution {
         hir::ScopeDef::ModuleDef(Function(func)) => {
             return render_fn(ctx, import_to_add, Some(local_name), *func);
@@ -197,10 +208,11 @@ fn render_resolution_(
         }
         hir::ScopeDef::Unknown => {
             let mut item = CompletionItem::new(
-                CompletionItemKind::UnresolvedReference,
+                CompletionKind::Reference,
                 ctx.source_range(),
                 local_name.to_string(),
             );
+            item.kind(CompletionItemKind::UnresolvedReference);
             if let Some(import_to_add) = import_to_add {
                 item.add_import(import_to_add);
             }
@@ -209,7 +221,7 @@ fn render_resolution_(
     };
 
     let local_name = local_name.to_string();
-    let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.clone());
+    let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
     if let hir::ScopeDef::Local(local) = resolution {
         let ty = local.ty(ctx.db());
         if !ty.is_unknown() {
@@ -248,7 +260,8 @@ fn render_resolution_(
             }
         }
     }
-    item.set_documentation(scope_def_docs(ctx.db(), resolution))
+    item.kind(kind)
+        .set_documentation(scope_def_docs(ctx.db(), resolution))
         .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
 
     if let Some(import_to_add) = import_to_add {
@@ -331,54 +344,37 @@ mod tests {
     use std::cmp;
 
     use expect_test::{expect, Expect};
-    use ide_db::SymbolKind;
     use itertools::Itertools;
 
     use crate::{
         item::CompletionRelevanceTypeMatch,
         tests::{check_edit, do_completion, get_all_items, TEST_CONFIG},
-        CompletionItem, CompletionItemKind, CompletionRelevance,
+        CompletionKind, CompletionRelevance,
     };
 
     #[track_caller]
-    fn check(ra_fixture: &str, kind: impl Into<CompletionItemKind>, expect: Expect) {
-        let actual = do_completion(ra_fixture, kind.into());
-        expect.assert_debug_eq(&actual);
-    }
-
-    #[track_caller]
-    fn check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
-        let actual: Vec<_> =
-            kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect();
+    fn check(ra_fixture: &str, expect: Expect) {
+        let actual = do_completion(ra_fixture, CompletionKind::Reference);
         expect.assert_debug_eq(&actual);
     }
 
     #[track_caller]
-    fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
-        let mut actual = get_all_items(TEST_CONFIG, ra_fixture);
-        actual.retain(|it| kinds.contains(&it.kind()));
-        actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
-        check_relevance_(actual, expect);
+    fn check_relevance(ra_fixture: &str, expect: Expect) {
+        check_relevance_for_kinds(&[CompletionKind::Reference], ra_fixture, expect)
     }
 
     #[track_caller]
-    fn check_relevance(ra_fixture: &str, expect: Expect) {
+    fn check_relevance_for_kinds(kinds: &[CompletionKind], ra_fixture: &str, expect: Expect) {
         let mut actual = get_all_items(TEST_CONFIG, ra_fixture);
-        actual.retain(|it| it.kind() != CompletionItemKind::Snippet);
-        actual.retain(|it| it.kind() != CompletionItemKind::Keyword);
-        actual.retain(|it| it.kind() != CompletionItemKind::BuiltinType);
+        actual.retain(|it| kinds.contains(&it.completion_kind));
         actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
-        check_relevance_(actual, expect);
-    }
 
-    #[track_caller]
-    fn check_relevance_(actual: Vec<CompletionItem>, expect: Expect) {
         let actual = actual
             .into_iter()
             .flat_map(|it| {
                 let mut items = vec![];
 
-                let tag = it.kind().tag();
+                let tag = it.kind().unwrap().tag();
                 let relevance = display_relevance(it.relevance());
                 items.push(format!("{} {} {}\n", tag, it.label(), relevance));
 
@@ -422,7 +418,6 @@ enum Foo { Foo { x: i32, y: i32 } }
 
 fn main() { Foo::Fo$0 }
 "#,
-            SymbolKind::Variant,
             expect![[r#"
                 [
                     CompletionItem {
@@ -448,7 +443,6 @@ enum Foo { Foo (i32, i32) }
 
 fn main() { Foo::Fo$0 }
 "#,
-            SymbolKind::Variant,
             expect![[r#"
                 [
                     CompletionItem {
@@ -476,7 +470,6 @@ fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
 
 fn main() { fo$0 }
 "#,
-            SymbolKind::Function,
             expect![[r#"
                 [
                     CompletionItem {
@@ -515,7 +508,6 @@ enum Foo { Foo }
 
 fn main() { Foo::Fo$0 }
 "#,
-            SymbolKind::Variant,
             expect![[r#"
                 [
                     CompletionItem {
@@ -535,40 +527,15 @@ fn main() { Foo::Fo$0 }
 
     #[test]
     fn lookup_enums_by_two_qualifiers() {
-        check_kinds(
+        check(
             r#"
 mod m {
     pub enum Spam { Foo, Bar(i32) }
 }
 fn main() { let _: m::Spam = S$0 }
 "#,
-            &[
-                CompletionItemKind::SymbolKind(SymbolKind::Function),
-                CompletionItemKind::SymbolKind(SymbolKind::Module),
-                CompletionItemKind::SymbolKind(SymbolKind::Variant),
-            ],
             expect![[r#"
                 [
-                    CompletionItem {
-                        label: "main()",
-                        source_range: 75..76,
-                        delete: 75..76,
-                        insert: "main()$0",
-                        kind: SymbolKind(
-                            Function,
-                        ),
-                        lookup: "main",
-                        detail: "fn()",
-                    },
-                    CompletionItem {
-                        label: "m",
-                        source_range: 75..76,
-                        delete: 75..76,
-                        insert: "m",
-                        kind: SymbolKind(
-                            Module,
-                        ),
-                    },
                     CompletionItem {
                         label: "Spam::Bar(…)",
                         source_range: 75..76,
@@ -589,6 +556,15 @@ fn main() { let _: m::Spam = S$0 }
                         },
                         trigger_call_info: true,
                     },
+                    CompletionItem {
+                        label: "m",
+                        source_range: 75..76,
+                        delete: 75..76,
+                        insert: "m",
+                        kind: SymbolKind(
+                            Module,
+                        ),
+                    },
                     CompletionItem {
                         label: "m::Spam::Foo",
                         source_range: 75..76,
@@ -608,6 +584,17 @@ fn main() { let _: m::Spam = S$0 }
                             exact_postfix_snippet_match: false,
                         },
                     },
+                    CompletionItem {
+                        label: "main()",
+                        source_range: 75..76,
+                        delete: 75..76,
+                        insert: "main()$0",
+                        kind: SymbolKind(
+                            Function,
+                        ),
+                        lookup: "main",
+                        detail: "fn()",
+                    },
                 ]
             "#]],
         )
@@ -624,7 +611,6 @@ fn something_else_deprecated() {}
 
 fn main() { som$0 }
 "#,
-            SymbolKind::Function,
             expect![[r#"
                 [
                     CompletionItem {
@@ -671,7 +657,6 @@ fn main() { som$0 }
 struct A { #[deprecated] the_field: u32 }
 fn foo() { A { the$0 } }
 "#,
-            SymbolKind::Field,
             expect![[r#"
                 [
                     CompletionItem {
@@ -700,7 +685,7 @@ fn foo() { A { the$0 } }
 
     #[test]
     fn renders_docs() {
-        check_kinds(
+        check(
             r#"
 struct S {
     /// Field docs
@@ -710,7 +695,6 @@ impl S {
     /// Method docs
     fn bar(self) { self.$0 }
 }"#,
-            &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
             expect![[r#"
                 [
                     CompletionItem {
@@ -742,7 +726,7 @@ impl S {
             "#]],
         );
 
-        check_kinds(
+        check(
             r#"
 use self::my$0;
 
@@ -756,23 +740,18 @@ enum E {
 }
 use self::E::*;
 "#,
-            &[
-                CompletionItemKind::SymbolKind(SymbolKind::Module),
-                CompletionItemKind::SymbolKind(SymbolKind::Variant),
-                CompletionItemKind::SymbolKind(SymbolKind::Enum),
-            ],
             expect![[r#"
                 [
                     CompletionItem {
-                        label: "my",
+                        label: "E",
                         source_range: 10..12,
                         delete: 10..12,
-                        insert: "my",
+                        insert: "E",
                         kind: SymbolKind(
-                            Module,
+                            Enum,
                         ),
                         documentation: Documentation(
-                            "mod docs",
+                            "enum docs",
                         ),
                     },
                     CompletionItem {
@@ -789,15 +768,15 @@ use self::E::*;
                         ),
                     },
                     CompletionItem {
-                        label: "E",
+                        label: "my",
                         source_range: 10..12,
                         delete: 10..12,
-                        insert: "E",
+                        insert: "my",
                         kind: SymbolKind(
-                            Enum,
+                            Module,
                         ),
                         documentation: Documentation(
-                            "enum docs",
+                            "mod docs",
                         ),
                     },
                 ]
@@ -816,7 +795,6 @@ impl S {
 }
 fn foo(s: S) { s.$0 }
 "#,
-            CompletionItemKind::Method,
             expect![[r#"
                 [
                     CompletionItem {
@@ -1340,28 +1318,18 @@ fn main() {
 
     #[test]
     fn struct_field_method_ref() {
-        check_kinds(
+        check(
             r#"
 struct Foo { bar: u32 }
 impl Foo { fn baz(&self) -> u32 { 0 } }
 
 fn foo(f: Foo) { let _: &u32 = f.b$0 }
 "#,
-            &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
             // FIXME
             // Ideally we'd also suggest &f.bar and &f.baz() as exact
             // type matches. See #8058.
             expect![[r#"
                 [
-                    CompletionItem {
-                        label: "baz()",
-                        source_range: 98..99,
-                        delete: 98..99,
-                        insert: "baz()$0",
-                        kind: Method,
-                        lookup: "baz",
-                        detail: "fn(&self) -> u32",
-                    },
                     CompletionItem {
                         label: "bar",
                         source_range: 98..99,
@@ -1372,6 +1340,15 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
                         ),
                         detail: "u32",
                     },
+                    CompletionItem {
+                        label: "baz()",
+                        source_range: 98..99,
+                        delete: 98..99,
+                        insert: "baz()$0",
+                        kind: Method,
+                        lookup: "baz",
+                        detail: "fn(&self) -> u32",
+                    },
                 ]
             "#]],
         );
@@ -1410,6 +1387,7 @@ fn foo() {
     #[test]
     fn postfix_completion_relevance() {
         check_relevance_for_kinds(
+            &[CompletionKind::Postfix, CompletionKind::Magic],
             r#"
 mod ops {
     pub trait Not {
@@ -1426,8 +1404,7 @@ mod ops {
 fn main() {
     let _: bool = (9 > 2).not$0;
 }
-    "#,
-            &[CompletionItemKind::Snippet, CompletionItemKind::Method],
+"#,
             expect![[r#"
                 sn not [snippet]
                 me not() (use ops::Not) [type_could_unify]
diff --git a/crates/ide_completion/src/render/const_.rs b/crates/ide_completion/src/render/const_.rs
index 241e0043c9..166ae3c16b 100644
--- a/crates/ide_completion/src/render/const_.rs
+++ b/crates/ide_completion/src/render/const_.rs
@@ -7,7 +7,10 @@ use syntax::{
     display::const_label,
 };
 
-use crate::{item::CompletionItem, render::RenderContext};
+use crate::{
+    item::{CompletionItem, CompletionKind},
+    render::RenderContext,
+};
 
 pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
     ConstRender::new(ctx, const_)?.render()
@@ -31,8 +34,9 @@ impl<'a> ConstRender<'a> {
         let detail = self.detail();
 
         let mut item =
-            CompletionItem::new(SymbolKind::Const, self.ctx.source_range(), name.clone());
-        item.set_documentation(self.ctx.docs(self.const_))
+            CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name.clone());
+        item.kind(SymbolKind::Const)
+            .set_documentation(self.ctx.docs(self.const_))
             .set_deprecated(
                 self.ctx.is_deprecated(self.const_)
                     || self.ctx.is_deprecated_assoc_item(self.const_),
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs
index 728e0e2a17..95768713cf 100644
--- a/crates/ide_completion/src/render/enum_variant.rs
+++ b/crates/ide_completion/src/render/enum_variant.rs
@@ -7,7 +7,7 @@ use ide_db::SymbolKind;
 use itertools::Itertools;
 
 use crate::{
-    item::{CompletionItem, ImportEdit},
+    item::{CompletionItem, CompletionKind, ImportEdit},
     render::{builder_ext::Params, compute_ref_match, compute_type_match, RenderContext},
     CompletionRelevance,
 };
@@ -61,11 +61,12 @@ impl<'a> EnumRender<'a> {
     }
     fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
         let mut item = CompletionItem::new(
-            SymbolKind::Variant,
+            CompletionKind::Reference,
             self.ctx.source_range(),
             self.qualified_name.to_string(),
         );
-        item.set_documentation(self.variant.docs(self.ctx.db()))
+        item.kind(SymbolKind::Variant)
+            .set_documentation(self.variant.docs(self.ctx.db()))
             .set_deprecated(self.ctx.is_deprecated(self.variant))
             .detail(self.detail());
 
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 7515bb6d47..769a0ed21f 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -7,7 +7,7 @@ use itertools::Itertools;
 use syntax::ast;
 
 use crate::{
-    item::{CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit},
+    item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit},
     render::{
         builder_ext::Params, compute_exact_name_match, compute_ref_match, compute_type_match,
         RenderContext,
@@ -79,8 +79,10 @@ impl<'a> FunctionRender<'a> {
             Some(receiver) => format!("{}.{}", receiver, &self.name),
             None => self.name.clone(),
         };
-        let mut item = CompletionItem::new(self.kind(), self.ctx.source_range(), call.clone());
-        item.set_documentation(self.ctx.docs(self.func))
+        let mut item =
+            CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), call.clone());
+        item.kind(self.kind())
+            .set_documentation(self.ctx.docs(self.func))
             .set_deprecated(
                 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
             )
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index b1ddfab0cb..196b667baa 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -6,7 +6,7 @@ use syntax::display::macro_label;
 
 use crate::{
     context::CallKind,
-    item::{CompletionItem, ImportEdit},
+    item::{CompletionItem, CompletionKind, ImportEdit},
     render::RenderContext,
 };
 
@@ -47,8 +47,9 @@ impl<'a> MacroRender<'a> {
         } else {
             Some(self.ctx.source_range())
         }?;
-        let mut item = CompletionItem::new(SymbolKind::Macro, source_range, &self.label());
-        item.set_documentation(self.docs.clone())
+        let mut item = CompletionItem::new(CompletionKind::Reference, source_range, &self.label());
+        item.kind(SymbolKind::Macro)
+            .set_documentation(self.docs.clone())
             .set_deprecated(self.ctx.is_deprecated(self.macro_))
             .set_detail(self.detail());
 
diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs
index b703280620..521296fd9b 100644
--- a/crates/ide_completion/src/render/pattern.rs
+++ b/crates/ide_completion/src/render/pattern.rs
@@ -6,6 +6,7 @@ use itertools::Itertools;
 
 use crate::{
     context::{ParamKind, PatternContext},
+    item::CompletionKind,
     render::RenderContext,
     CompletionItem, CompletionItemKind,
 };
@@ -57,8 +58,11 @@ fn build_completion(
     pat: String,
     def: impl HasAttrs + Copy,
 ) -> CompletionItem {
-    let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), name);
-    item.set_documentation(ctx.docs(def)).set_deprecated(ctx.is_deprecated(def)).detail(&pat);
+    let mut item = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name);
+    item.kind(CompletionItemKind::Binding)
+        .set_documentation(ctx.docs(def))
+        .set_deprecated(ctx.is_deprecated(def))
+        .detail(&pat);
     match ctx.snippet_cap() {
         Some(snippet_cap) => item.insert_snippet(snippet_cap, pat),
         None => item.insert_text(pat),
diff --git a/crates/ide_completion/src/render/struct_literal.rs b/crates/ide_completion/src/render/struct_literal.rs
index 4eb4f6b9f1..810b51effd 100644
--- a/crates/ide_completion/src/render/struct_literal.rs
+++ b/crates/ide_completion/src/render/struct_literal.rs
@@ -4,7 +4,7 @@ use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
 use ide_db::helpers::SnippetCap;
 use itertools::Itertools;
 
-use crate::{render::RenderContext, CompletionItem, CompletionItemKind};
+use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind};
 
 pub(crate) fn render_struct_literal(
     ctx: RenderContext<'_>,
@@ -33,9 +33,11 @@ fn build_completion(
     literal: String,
     def: impl HasAttrs + Copy,
 ) -> CompletionItem {
-    let mut item =
-        CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), name + " {…}");
-    item.set_documentation(ctx.docs(def)).set_deprecated(ctx.is_deprecated(def)).detail(&literal);
+    let mut item = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name + " {…}");
+    item.kind(CompletionItemKind::Snippet)
+        .set_documentation(ctx.docs(def))
+        .set_deprecated(ctx.is_deprecated(def))
+        .detail(&literal);
     match ctx.snippet_cap() {
         Some(snippet_cap) => item.insert_snippet(snippet_cap, literal),
         None => item.insert_text(literal),
diff --git a/crates/ide_completion/src/render/type_alias.rs b/crates/ide_completion/src/render/type_alias.rs
index 7b6d2fa5c3..c1e6182643 100644
--- a/crates/ide_completion/src/render/type_alias.rs
+++ b/crates/ide_completion/src/render/type_alias.rs
@@ -7,7 +7,10 @@ use syntax::{
     display::type_label,
 };
 
-use crate::{item::CompletionItem, render::RenderContext};
+use crate::{
+    item::{CompletionItem, CompletionKind},
+    render::RenderContext,
+};
 
 pub(crate) fn render_type_alias(
     ctx: RenderContext<'_>,
@@ -47,8 +50,9 @@ impl<'a> TypeAliasRender<'a> {
         let detail = self.detail();
 
         let mut item =
-            CompletionItem::new(SymbolKind::TypeAlias, self.ctx.source_range(), name.clone());
-        item.set_documentation(self.ctx.docs(self.type_alias))
+            CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name.clone());
+        item.kind(SymbolKind::TypeAlias)
+            .set_documentation(self.ctx.docs(self.type_alias))
             .set_deprecated(
                 self.ctx.is_deprecated(self.type_alias)
                     || self.ctx.is_deprecated_assoc_item(self.type_alias),
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index 5bc8e8764f..effa694aae 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -12,10 +12,10 @@ use hir::{
 };
 use syntax::{
     ast::{self, AstNode},
-    match_ast, AstToken, SyntaxKind, SyntaxNode, SyntaxToken,
+    match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
 };
 
-use crate::{helpers::try_resolve_derive_input, RootDatabase};
+use crate::{helpers::try_resolve_derive_input_at, RootDatabase};
 
 // FIXME: a more precise name would probably be `Symbol`?
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
@@ -38,20 +38,19 @@ impl Definition {
             Some(parent) => parent,
             None => return Default::default(),
         };
-        if let Some(ident) = ast::Ident::cast(token.clone()) {
-            let attr = parent
-                .ancestors()
-                .find_map(ast::TokenTree::cast)
-                .and_then(|tt| tt.parent_meta())
-                .and_then(|meta| meta.parent_attr());
-            if let Some(attr) = attr {
-                return try_resolve_derive_input(&sema, &attr, &ident)
-                    .map(Into::into)
-                    .into_iter()
-                    .collect();
-            }
+        let attr = parent
+            .ancestors()
+            .find_map(ast::TokenTree::cast)
+            .and_then(|tt| tt.parent_meta())
+            .and_then(|meta| meta.parent_attr());
+        if let Some(attr) = attr {
+            try_resolve_derive_input_at(&sema, &attr, &token)
+                .map(Definition::Macro)
+                .into_iter()
+                .collect()
+        } else {
+            Self::from_node(sema, &parent)
         }
-        Self::from_node(sema, &parent)
     }
 
     pub fn from_node(sema: &Semantics<RootDatabase>, node: &SyntaxNode) -> ArrayVec<Definition, 2> {
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index f6a1a55218..173e55b33f 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -7,16 +7,14 @@ pub mod merge_imports;
 pub mod node_ext;
 pub mod rust_doc;
 
-use std::{collections::VecDeque, iter};
+use std::collections::VecDeque;
 
 use base_db::FileId;
 use either::Either;
-use hir::{ItemInNs, MacroDef, ModuleDef, Name, PathResolution, Semantics};
-use itertools::Itertools;
+use hir::{ItemInNs, MacroDef, ModuleDef, Name, Semantics};
 use syntax::{
-    ast::{self, make, HasLoopBody, Ident},
-    AstNode, AstToken, Direction, SyntaxElement, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent,
-    T,
+    ast::{self, make, HasLoopBody},
+    AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent, T,
 };
 
 use crate::RootDatabase;
@@ -31,59 +29,33 @@ pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
     }
 }
 
-/// Parses and returns the derive path at the cursor position in the given attribute, if it is a derive.
-/// This special case is required because the derive macro is a compiler builtin that discards the input derives.
-///
-/// The returned path is synthesized from TokenTree tokens and as such cannot be used with the [`Semantics`].
-pub fn get_path_in_derive_attr(
+/// Resolves the path at the cursor token as a derive macro if it inside a token tree of a derive attribute.
+pub fn try_resolve_derive_input_at(
     sema: &hir::Semantics<RootDatabase>,
-    attr: &ast::Attr,
-    cursor: &Ident,
-) -> Option<ast::Path> {
-    let cursor = cursor.syntax();
-    let path = attr.path()?;
-    let tt = attr.token_tree()?;
-    if !tt.syntax().text_range().contains_range(cursor.text_range()) {
+    derive_attr: &ast::Attr,
+    cursor: &SyntaxToken,
+) -> Option<MacroDef> {
+    use itertools::Itertools;
+    if cursor.kind() != T![ident] {
         return None;
     }
-    let scope = sema.scope(attr.syntax());
-    let resolved_attr = sema.resolve_path(&path)?;
-    let derive = FamousDefs(sema, scope.krate()).core_macros_builtin_derive()?;
-    if PathResolution::Macro(derive) != resolved_attr {
-        return None;
-    }
-
-    let first = cursor
+    let tt = match derive_attr.as_simple_call() {
+        Some((name, tt))
+            if name == "derive" && tt.syntax().text_range().contains_range(cursor.text_range()) =>
+        {
+            tt
+        }
+        _ => return None,
+    };
+    let tokens: Vec<_> = cursor
         .siblings_with_tokens(Direction::Prev)
-        .filter_map(SyntaxElement::into_token)
+        .flat_map(SyntaxElement::into_token)
         .take_while(|tok| tok.kind() != T!['('] && tok.kind() != T![,])
-        .last()?;
-    let path_tokens = first
-        .siblings_with_tokens(Direction::Next)
-        .filter_map(SyntaxElement::into_token)
-        .take_while(|tok| tok != cursor);
-
-    ast::Path::parse(&path_tokens.chain(iter::once(cursor.clone())).join("")).ok()
-}
-
-/// Parses and resolves the path at the cursor position in the given attribute, if it is a derive.
-/// This special case is required because the derive macro is a compiler builtin that discards the input derives.
-pub fn try_resolve_derive_input(
-    sema: &hir::Semantics<RootDatabase>,
-    attr: &ast::Attr,
-    cursor: &Ident,
-) -> Option<PathResolution> {
-    let path = get_path_in_derive_attr(sema, attr, cursor)?;
-    let scope = sema.scope(attr.syntax());
-    // FIXME: This double resolve shouldn't be necessary
-    // It's only here so we prefer macros over other namespaces
-    match scope.speculative_resolve_as_mac(&path) {
-        Some(mac) if mac.kind() == hir::MacroKind::Derive => Some(PathResolution::Macro(mac)),
-        Some(_) => return None,
-        None => scope
-            .speculative_resolve(&path)
-            .filter(|res| matches!(res, PathResolution::Def(ModuleDef::Module(_)))),
-    }
+        .collect();
+    let path = ast::Path::parse(&tokens.into_iter().rev().join("")).ok()?;
+    sema.scope(tt.syntax())
+        .speculative_resolve_as_mac(&path)
+        .filter(|mac| mac.kind() == hir::MacroKind::Derive)
 }
 
 /// Picks the token with the highest rank returned by the passed in function.
diff --git a/crates/ide_db/src/helpers/famous_defs.rs b/crates/ide_db/src/helpers/famous_defs.rs
index e8993d327f..b5e3907cfa 100644
--- a/crates/ide_db/src/helpers/famous_defs.rs
+++ b/crates/ide_db/src/helpers/famous_defs.rs
@@ -1,5 +1,5 @@
 //! See [`FamousDefs`].
-use hir::{Crate, Enum, MacroDef, Module, ScopeDef, Semantics, Trait};
+use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
 
 use crate::RootDatabase;
 
@@ -80,10 +80,6 @@ impl FamousDefs<'_, '_> {
         self.find_trait("core:marker:Copy")
     }
 
-    pub fn core_macros_builtin_derive(&self) -> Option<MacroDef> {
-        self.find_macro("core:macros:builtin:derive")
-    }
-
     pub fn alloc(&self) -> Option<Crate> {
         self.find_crate("alloc")
     }
@@ -114,13 +110,6 @@ impl FamousDefs<'_, '_> {
         }
     }
 
-    fn find_macro(&self, path: &str) -> Option<MacroDef> {
-        match self.find_def(path)? {
-            hir::ScopeDef::MacroDef(it) => Some(it),
-            _ => None,
-        }
-    }
-
     fn find_enum(&self, path: &str) -> Option<Enum> {
         match self.find_def(path)? {
             hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 0b3ecd095b..f1e8ee4935 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -8,11 +8,10 @@ use rustc_hash::FxHashSet;
 use syntax::{
     ast::{self, HasName},
     utils::path_to_string_stripping_turbo_fish,
-    AstNode, AstToken, SyntaxNode,
+    AstNode, SyntaxNode,
 };
 
 use crate::{
-    helpers::get_path_in_derive_attr,
     items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT},
     RootDatabase,
 };
@@ -120,7 +119,7 @@ impl ImportAssets {
         })
     }
 
-    pub fn for_ident_pat(sema: &Semantics<RootDatabase>, pat: &ast::IdentPat) -> Option<Self> {
+    pub fn for_ident_pat(pat: &ast::IdentPat, sema: &Semantics<RootDatabase>) -> Option<Self> {
         if !pat.is_simple_ident() {
             return None;
         }
@@ -133,22 +132,6 @@ impl ImportAssets {
         })
     }
 
-    pub fn for_derive_ident(sema: &Semantics<RootDatabase>, ident: &ast::Ident) -> Option<Self> {
-        let attr = ident.syntax().ancestors().find_map(ast::Attr::cast)?;
-        let path = get_path_in_derive_attr(sema, &attr, ident)?;
-
-        if let Some(_) = path.qualifier() {
-            return None;
-        }
-        let name = NameToImport::Exact(path.segment()?.name_ref()?.to_string());
-        let candidate_node = attr.syntax().clone();
-        Some(Self {
-            import_candidate: ImportCandidate::Path(PathImportCandidate { qualifier: None, name }),
-            module_with_candidate: sema.scope(&candidate_node).module()?,
-            candidate_node,
-        })
-    }
-
     pub fn for_fuzzy_path(
         module_with_candidate: Module,
         qualifier: Option<ast::Path>,
diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs
index 1e1bfa5505..7244d21161 100644
--- a/crates/mbe/src/expander.rs
+++ b/crates/mbe/src/expander.rs
@@ -110,12 +110,7 @@ enum Binding {
 enum Fragment {
     /// token fragments are just copy-pasted into the output
     Tokens(tt::TokenTree),
-    /// Expr ast fragments are surrounded with `()` on insertion to preserve
-    /// precedence. Note that this impl is different from the one currently in
-    /// `rustc` -- `rustc` doesn't translate fragments into token trees at all.
-    ///
-    /// At one point in time, we tried to to use "fake" delimiters here a-la
-    /// proc-macro delimiter=none. As we later discovered, "none" delimiters are
-    /// tricky to handle in the parser, and rustc doesn't handle those either.
-    Expr(tt::TokenTree),
+    /// Ast fragments are inserted with fake delimiters, so as to make things
+    /// like `$i * 2` where `$i = 1 + 1` work as expectd.
+    Ast(tt::TokenTree),
 }
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index b2d3f038f5..06c21dfd70 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -736,7 +736,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
         }
     };
     let result = input.expect_fragment(fragment);
-    result.map(|tt| if kind == "expr" { tt.map(Fragment::Expr) } else { tt.map(Fragment::Tokens) })
+    result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) })
 }
 
 fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) {
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index 0db17fea6e..8140f25b06 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -238,16 +238,7 @@ fn expand_repeat(
 fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
     match fragment {
         Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
-        Fragment::Expr(tt::TokenTree::Subtree(mut tt)) => {
-            if tt.delimiter.is_none() {
-                tt.delimiter = Some(tt::Delimiter {
-                    id: tt::TokenId::unspecified(),
-                    kind: tt::DelimiterKind::Parenthesis,
-                })
-            }
-            buf.push(tt.into())
-        }
-        Fragment::Tokens(tt) | Fragment::Expr(tt) => buf.push(tt),
+        Fragment::Tokens(tt) | Fragment::Ast(tt) => buf.push(tt),
     }
 }
 
diff --git a/crates/mbe/src/subtree_source.rs b/crates/mbe/src/subtree_source.rs
index 6bdd787e30..247616aa1b 100644
--- a/crates/mbe/src/subtree_source.rs
+++ b/crates/mbe/src/subtree_source.rs
@@ -52,20 +52,17 @@ impl<'a> SubtreeTokenSource {
                     cursor.bump()
                 }
                 Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
-                    if let Some(d) = subtree.delimiter_kind() {
-                        cached.push(convert_delim(d, false));
-                    }
+                    cached.push(convert_delim(subtree.delimiter_kind(), false));
                     cursor.subtree().unwrap()
                 }
-                None => match cursor.end() {
-                    Some(subtree) => {
-                        if let Some(d) = subtree.delimiter_kind() {
-                            cached.push(convert_delim(d, true));
-                        }
+                None => {
+                    if let Some(subtree) = cursor.end() {
+                        cached.push(convert_delim(subtree.delimiter_kind(), true));
                         cursor.bump()
+                    } else {
+                        continue;
                     }
-                    None => continue,
-                },
+                }
             };
         }
 
@@ -112,16 +109,17 @@ impl<'a> TokenSource for SubtreeTokenSource {
     }
 }
 
-fn convert_delim(d: tt::DelimiterKind, closing: bool) -> TtToken {
+fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken {
     let (kinds, texts) = match d {
-        tt::DelimiterKind::Parenthesis => ([T!['('], T![')']], "()"),
-        tt::DelimiterKind::Brace => ([T!['{'], T!['}']], "{}"),
-        tt::DelimiterKind::Bracket => ([T!['['], T![']']], "[]"),
+        Some(tt::DelimiterKind::Parenthesis) => ([T!['('], T![')']], "()"),
+        Some(tt::DelimiterKind::Brace) => ([T!['{'], T!['}']], "{}"),
+        Some(tt::DelimiterKind::Bracket) => ([T!['['], T![']']], "[]"),
+        None => ([L_DOLLAR, R_DOLLAR], ""),
     };
 
     let idx = closing as usize;
     let kind = kinds[idx];
-    let text = &texts[idx..texts.len() - (1 - idx)];
+    let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" };
     TtToken { tt: Token { kind, is_jointed_to_next: false }, text: SmolStr::new(text) }
 }
 
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 0b65fa171f..6bd57bb568 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -632,11 +632,12 @@ impl<'a> TtTreeSink<'a> {
     }
 }
 
-fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> &'static str {
+fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> &'static str {
     let texts = match d {
-        tt::DelimiterKind::Parenthesis => "()",
-        tt::DelimiterKind::Brace => "{}",
-        tt::DelimiterKind::Bracket => "[]",
+        Some(tt::DelimiterKind::Parenthesis) => "()",
+        Some(tt::DelimiterKind::Brace) => "{}",
+        Some(tt::DelimiterKind::Bracket) => "[]",
+        None => return "",
     };
 
     let idx = closing as usize;
@@ -645,6 +646,10 @@ fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> &'static str {
 
 impl<'a> TreeSink for TtTreeSink<'a> {
     fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) {
+        if kind == L_DOLLAR || kind == R_DOLLAR {
+            self.cursor = self.cursor.bump_subtree();
+            return;
+        }
         if kind == LIFETIME_IDENT {
             n_tokens = 2;
         }
@@ -656,54 +661,48 @@ impl<'a> TreeSink for TtTreeSink<'a> {
                 break;
             }
             last = self.cursor;
-            let text: &str = loop {
-                break match self.cursor.token_tree() {
-                    Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => {
-                        // Mark the range if needed
-                        let (text, id) = match leaf {
-                            tt::Leaf::Ident(ident) => (&ident.text, ident.id),
-                            tt::Leaf::Punct(punct) => {
-                                assert!(punct.char.is_ascii());
-                                let char = &(punct.char as u8);
-                                tmp_str = SmolStr::new_inline(
-                                    std::str::from_utf8(std::slice::from_ref(char)).unwrap(),
-                                );
-                                (&tmp_str, punct.id)
-                            }
-                            tt::Leaf::Literal(lit) => (&lit.text, lit.id),
-                        };
-                        let range = TextRange::at(self.text_pos, TextSize::of(text.as_str()));
-                        self.token_map.insert(id, range);
-                        self.cursor = self.cursor.bump();
-                        text
-                    }
-                    Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
-                        self.cursor = self.cursor.subtree().unwrap();
-                        match subtree.delimiter {
-                            Some(d) => {
-                                self.open_delims.insert(d.id, self.text_pos);
-                                delim_to_str(d.kind, false)
-                            }
-                            None => continue,
+            let text: &str = match self.cursor.token_tree() {
+                Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => {
+                    // Mark the range if needed
+                    let (text, id) = match leaf {
+                        tt::Leaf::Ident(ident) => (&ident.text, ident.id),
+                        tt::Leaf::Punct(punct) => {
+                            assert!(punct.char.is_ascii());
+                            let char = &(punct.char as u8);
+                            tmp_str = SmolStr::new_inline(
+                                std::str::from_utf8(std::slice::from_ref(char)).unwrap(),
+                            );
+                            (&tmp_str, punct.id)
                         }
+                        tt::Leaf::Literal(lit) => (&lit.text, lit.id),
+                    };
+                    let range = TextRange::at(self.text_pos, TextSize::of(text.as_str()));
+                    self.token_map.insert(id, range);
+                    self.cursor = self.cursor.bump();
+                    text
+                }
+                Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
+                    self.cursor = self.cursor.subtree().unwrap();
+                    if let Some(id) = subtree.delimiter.map(|it| it.id) {
+                        self.open_delims.insert(id, self.text_pos);
                     }
-                    None => {
-                        let parent = self.cursor.end().unwrap();
+                    delim_to_str(subtree.delimiter_kind(), false)
+                }
+                None => {
+                    if let Some(parent) = self.cursor.end() {
                         self.cursor = self.cursor.bump();
-                        match parent.delimiter {
-                            Some(d) => {
-                                if let Some(open_delim) = self.open_delims.get(&d.id) {
-                                    let open_range = TextRange::at(*open_delim, TextSize::of('('));
-                                    let close_range =
-                                        TextRange::at(self.text_pos, TextSize::of('('));
-                                    self.token_map.insert_delim(d.id, open_range, close_range);
-                                }
-                                delim_to_str(d.kind, true)
+                        if let Some(id) = parent.delimiter.map(|it| it.id) {
+                            if let Some(open_delim) = self.open_delims.get(&id) {
+                                let open_range = TextRange::at(*open_delim, TextSize::of('('));
+                                let close_range = TextRange::at(self.text_pos, TextSize::of('('));
+                                self.token_map.insert_delim(id, open_range, close_range);
                             }
-                            None => continue,
                         }
+                        delim_to_str(parent.delimiter_kind(), true)
+                    } else {
+                        continue;
                     }
-                };
+                }
             };
             self.buf += text;
             self.text_pos += TextSize::of(text);
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index 640caa0778..7075ae297f 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -39,6 +39,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
         T!['('],
         T!['{'],
         T!['['],
+        L_DOLLAR,
         T![|],
         T![move],
         T![box],
@@ -58,7 +59,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
         LIFETIME_IDENT,
     ]));
 
-const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![let]]);
+const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![let], R_DOLLAR]);
 
 pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
     if let Some(m) = literal(p) {
@@ -71,6 +72,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
     let done = match p.current() {
         T!['('] => tuple_expr(p),
         T!['['] => array_expr(p),
+        L_DOLLAR => meta_var_expr(p),
         T![|] => closure_expr(p),
         T![move] if la == T![|] => closure_expr(p),
         T![async] if la == T![|] || (la == T![move] && p.nth(2) == T![|]) => closure_expr(p),
@@ -620,3 +622,27 @@ fn box_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
     }
     m.complete(p, BOX_EXPR)
 }
+
+/// Expression from `$var` macro expansion, wrapped in dollars
+fn meta_var_expr(p: &mut Parser) -> CompletedMarker {
+    assert!(p.at(L_DOLLAR));
+    let m = p.start();
+    p.bump(L_DOLLAR);
+    let expr = expr_bp(p, None, Restrictions { forbid_structs: false, prefer_stmt: false }, 1);
+
+    match (expr, p.current()) {
+        (Some((cm, _)), R_DOLLAR) => {
+            p.bump(R_DOLLAR);
+            // FIXME: this leaves the dollar hanging in the air...
+            m.abandon(p);
+            cm
+        }
+        _ => {
+            while !p.at(R_DOLLAR) {
+                p.bump_any();
+            }
+            p.bump(R_DOLLAR);
+            m.complete(p, ERROR)
+        }
+    }
+}
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index 05c1aea5c4..1a6fb651cb 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -19,6 +19,7 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
 const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
     T![')'],
     T![,],
+    L_DOLLAR,
     // test_err struct_field_recover
     // struct S { f pub g: () }
     T![pub],
diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs
index 5820ffd77d..89dfea52f8 100644
--- a/crates/parser/src/parser.rs
+++ b/crates/parser/src/parser.rs
@@ -7,7 +7,7 @@ use drop_bomb::DropBomb;
 use crate::{
     event::Event,
     ParseError,
-    SyntaxKind::{self, EOF, ERROR, TOMBSTONE},
+    SyntaxKind::{self, EOF, ERROR, L_DOLLAR, R_DOLLAR, TOMBSTONE},
     TokenSet, TokenSource, T,
 };
 
@@ -215,13 +215,23 @@ impl<'t> Parser<'t> {
 
     /// Create an error node and consume the next token.
     pub(crate) fn err_and_bump(&mut self, message: &str) {
-        self.err_recover(message, TokenSet::EMPTY);
+        match self.current() {
+            L_DOLLAR | R_DOLLAR => {
+                let m = self.start();
+                self.error(message);
+                self.bump_any();
+                m.complete(self, ERROR);
+            }
+            _ => {
+                self.err_recover(message, TokenSet::EMPTY);
+            }
+        }
     }
 
     /// Create an error node and consume the next token.
     pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) {
         match self.current() {
-            T!['{'] | T!['}'] => {
+            T!['{'] | T!['}'] | L_DOLLAR | R_DOLLAR => {
                 self.error(message);
                 return;
             }
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index 99e7651906..a9010c0c31 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -120,6 +120,8 @@ pub enum SyntaxKind {
     LIFETIME_IDENT,
     COMMENT,
     SHEBANG,
+    L_DOLLAR,
+    R_DOLLAR,
     SOURCE_FILE,
     STRUCT,
     UNION,
diff --git a/crates/proc_macro_api/src/lib.rs b/crates/proc_macro_api/src/lib.rs
index 9e50c1f83f..b03a029f8a 100644
--- a/crates/proc_macro_api/src/lib.rs
+++ b/crates/proc_macro_api/src/lib.rs
@@ -167,7 +167,7 @@ impl ProcMacro {
         let request = msg::Request::ExpandMacro(task);
         let response = self.process.lock().unwrap_or_else(|e| e.into_inner()).send_task(request)?;
         match response {
-            msg::Response::ExpandMacro(it) => Ok(it.map(FlatTree::to_subtree)),
+            msg::Response::ExpandMacro(it) => Ok(it.map(|it| it.to_subtree())),
             msg::Response::ListMacros { .. } => {
                 Err(ServerError { message: "unexpected response".to_string(), io: None })
             }
diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs
index f108b694c0..f3b843dc08 100644
--- a/crates/rust-analyzer/src/cli/lsif.rs
+++ b/crates/rust-analyzer/src/cli/lsif.rs
@@ -136,7 +136,6 @@ impl LsifManager<'_> {
                 result: lsp_types::Hover {
                     contents: lsp_types::HoverContents::Markup(to_proto::markup_content(
                         hover.markup,
-                        ide::HoverDocFormat::Markdown,
                     )),
                     range: None,
                 },
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 81f4ccd365..0d6b1bcbfb 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -1289,29 +1289,6 @@ mod tests {
             .to_string();
         schema.push_str(",\n");
 
-        // Transform the asciidoc form link to markdown style.
-        //
-        // https://link[text] => [text](https://link)
-        let url_matches = schema.match_indices("https://");
-        let mut url_offsets = url_matches.map(|(idx, _)| idx).collect::<Vec<usize>>();
-        url_offsets.reverse();
-        for idx in url_offsets {
-            let link = &schema[idx..];
-            // matching on whitespace to ignore normal links
-            if let Some(link_end) = link.find(|c| c == ' ' || c == '[') {
-                if link.chars().nth(link_end) == Some('[') {
-                    if let Some(link_text_end) = link.find(']') {
-                        let link_text = link[link_end..(link_text_end + 1)].to_string();
-
-                        schema.replace_range((idx + link_end)..(idx + link_text_end + 1), "");
-                        schema.insert(idx, '(');
-                        schema.insert(idx + link_end + 1, ')');
-                        schema.insert_str(idx, &link_text);
-                    }
-                }
-            }
-        }
-
         let package_json_path = project_root().join("editors/code/package.json");
         let mut package_json = fs::read_to_string(&package_json_path).unwrap();
 
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 0ddddeca67..ba4b153cfc 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -920,14 +920,9 @@ pub(crate) fn handle_hover(
 
     let line_index = snap.file_line_index(file_range.file_id)?;
     let range = to_proto::range(&line_index, info.range);
-    let markup_kind =
-        snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind);
     let hover = lsp_ext::Hover {
         hover: lsp_types::Hover {
-            contents: HoverContents::Markup(to_proto::markup_content(
-                info.info.markup,
-                markup_kind,
-            )),
+            contents: HoverContents::Markup(to_proto::markup_content(info.info.markup)),
             range: Some(range),
         },
         actions: if snap.config.hover_actions().none() {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 8e77df9598..b17711d6a6 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -248,7 +248,7 @@ fn completion_item(
         label: item.label().to_string(),
         detail: item.detail().map(|it| it.to_string()),
         filter_text: Some(item.lookup().to_string()),
-        kind: Some(completion_item_kind(item.kind())),
+        kind: item.kind().map(completion_item_kind),
         text_edit: Some(text_edit),
         additional_text_edits: Some(additional_text_edits),
         documentation: item.documentation().map(documentation),
@@ -673,7 +673,7 @@ pub(crate) fn location(
     Ok(loc)
 }
 
-/// Prefer using `location_link`, if the client has the cap.
+/// Perefer using `location_link`, if the client has the cap.
 pub(crate) fn location_from_nav(
     snap: &GlobalStateSnapshot,
     nav: NavigationTarget,
@@ -1202,16 +1202,9 @@ pub(crate) fn reference_title(count: usize) -> String {
     }
 }
 
-pub(crate) fn markup_content(
-    markup: Markup,
-    kind: ide::HoverDocFormat,
-) -> lsp_types::MarkupContent {
-    let kind = match kind {
-        ide::HoverDocFormat::Markdown => lsp_types::MarkupKind::Markdown,
-        ide::HoverDocFormat::PlainText => lsp_types::MarkupKind::PlainText,
-    };
+pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent {
     let value = crate::markdown::format_docs(markup.as_str());
-    lsp_types::MarkupContent { kind, value }
+    lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value }
 }
 
 pub(crate) fn rename_error(err: RenameError) -> crate::LspError {
diff --git a/crates/syntax/src/ast/generated/tokens.rs b/crates/syntax/src/ast/generated/tokens.rs
index 30f23b9d96..83fd5ce899 100644
--- a/crates/syntax/src/ast/generated/tokens.rs
+++ b/crates/syntax/src/ast/generated/tokens.rs
@@ -131,24 +131,3 @@ impl AstToken for FloatNumber {
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Ident {
-    pub(crate) syntax: SyntaxToken,
-}
-impl std::fmt::Display for Ident {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        std::fmt::Display::fmt(&self.syntax, f)
-    }
-}
-impl AstToken for Ident {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT }
-    fn cast(syntax: SyntaxToken) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
-    }
-    fn syntax(&self) -> &SyntaxToken { &self.syntax }
-}
diff --git a/editors/code/package.json b/editors/code/package.json
index 336081e88c..5dcdcb2769 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -436,7 +436,7 @@
                     ]
                 },
                 "rust-analyzer.assist.importGroup": {
-                    "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.",
+                    "markdownDescription": "Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.",
                     "default": true,
                     "type": "boolean"
                 },


Test patch:
diff --git a/crates/hir_def/src/macro_expansion_tests/mbe.rs b/crates/hir_def/src/macro_expansion_tests/mbe.rs
index 953750d360..7a866135b3 100644
--- a/crates/hir_def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir_def/src/macro_expansion_tests/mbe.rs
@@ -317,35 +317,32 @@ macro_rules! m {
     ($ i:expr) => { fn bar() { $ i * 3; } }
 }
 fn bar() {
-    (1+2)*3;
+    1+2*3;
 }
-// MACRO_ITEMS@0..17
-//   FN@0..17
+// MACRO_ITEMS@0..15
+//   FN@0..15
 //     FN_KW@0..2 "fn"
 //     NAME@2..5
 //       IDENT@2..5 "bar"
 //     PARAM_LIST@5..7
 //       L_PAREN@5..6 "("
 //       R_PAREN@6..7 ")"
-//     BLOCK_EXPR@7..17
-//       STMT_LIST@7..17
+//     BLOCK_EXPR@7..15
+//       STMT_LIST@7..15
 //         L_CURLY@7..8 "{"
-//         EXPR_STMT@8..16
-//           BIN_EXPR@8..15
-//             PAREN_EXPR@8..13
-//               L_PAREN@8..9 "("
-//               BIN_EXPR@9..12
-//                 LITERAL@9..10
-//                   INT_NUMBER@9..10 "1"
-//                 PLUS@10..11 "+"
-//                 LITERAL@11..12
-//                   INT_NUMBER@11..12 "2"
-//               R_PAREN@12..13 ")"
-//             STAR@13..14 "*"
-//             LITERAL@14..15
-//               INT_NUMBER@14..15 "3"
-//           SEMICOLON@15..16 ";"
-//         R_CURLY@16..17 "}"
+//         EXPR_STMT@8..14
+//           BIN_EXPR@8..13
+//             BIN_EXPR@8..11
+//               LITERAL@8..9
+//                 INT_NUMBER@8..9 "1"
+//               PLUS@9..10 "+"
+//               LITERAL@10..11
+//                 INT_NUMBER@10..11 "2"
+//             STAR@11..12 "*"
+//             LITERAL@12..13
+//               INT_NUMBER@12..13 "3"
+//           SEMICOLON@13..14 ";"
+//         R_CURLY@14..15 "}"
 
 "#]],
     )
@@ -725,7 +722,7 @@ macro_rules! m {
 }
 
 fn bar() {
-    (2+2*baz(3).quux());
+    2+2*baz(3).quux();
 }
 "#]],
     )
@@ -1373,48 +1370,42 @@ macro_rules! m {
 }
 /* parse error: expected identifier */
 /* parse error: expected SEMICOLON */
-/* parse error: expected SEMICOLON */
-/* parse error: expected expression */
 fn f() {
-    K::(C("0"));
+    K::C("0");
 }
-// MACRO_ITEMS@0..19
-//   FN@0..19
+// MACRO_ITEMS@0..17
+//   FN@0..17
 //     FN_KW@0..2 "fn"
 //     NAME@2..3
 //       IDENT@2..3 "f"
 //     PARAM_LIST@3..5
 //       L_PAREN@3..4 "("
 //       R_PAREN@4..5 ")"
-//     BLOCK_EXPR@5..19
-//       STMT_LIST@5..19
+//     BLOCK_EXPR@5..17
+//       STMT_LIST@5..17
 //         L_CURLY@5..6 "{"
-//         EXPR_STMT@6..10
-//           PATH_EXPR@6..10
-//             PATH@6..10
+//         EXPR_STMT@6..9
+//           PATH_EXPR@6..9
+//             PATH@6..9
 //               PATH@6..7
 //                 PATH_SEGMENT@6..7
 //                   NAME_REF@6..7
 //                     IDENT@6..7 "K"
 //               COLON2@7..9 "::"
-//               ERROR@9..10
-//                 L_PAREN@9..10 "("
-//         EXPR_STMT@10..16
-//           CALL_EXPR@10..16
-//             PATH_EXPR@10..11
-//               PATH@10..11
-//                 PATH_SEGMENT@10..11
-//                   NAME_REF@10..11
-//                     IDENT@10..11 "C"
-//             ARG_LIST@11..16
-//               L_PAREN@11..12 "("
-//               LITERAL@12..15
-//                 STRING@12..15 "\"0\""
-//               R_PAREN@15..16 ")"
-//         ERROR@16..17
-//           R_PAREN@16..17 ")"
-//         SEMICOLON@17..18 ";"
-//         R_CURLY@18..19 "}"
+//         EXPR_STMT@9..16
+//           CALL_EXPR@9..15
+//             PATH_EXPR@9..10
+//               PATH@9..10
+//                 PATH_SEGMENT@9..10
+//                   NAME_REF@9..10
+//                     IDENT@9..10 "C"
+//             ARG_LIST@10..15
+//               L_PAREN@10..11 "("
+//               LITERAL@11..14
+//                 STRING@11..14 "\"0\""
+//               R_PAREN@14..15 ")"
+//           SEMICOLON@15..16 ";"
+//         R_CURLY@16..17 "}"
 
 "#]],
     );
@@ -1450,7 +1441,7 @@ fn f() {
         expect![[r#"
 macro_rules! m { ($expr:expr) => { map($expr) } }
 fn f() {
-    let _ = map((x+foo));
+    let _ = map(x+foo);
 }
 "#]],
     )
diff --git a/crates/hir_def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir_def/src/macro_expansion_tests/mbe/regression.rs
index 2dff4adf2e..563fe50588 100644
--- a/crates/hir_def/src/macro_expansion_tests/mbe/regression.rs
+++ b/crates/hir_def/src/macro_expansion_tests/mbe/regression.rs
@@ -825,18 +825,15 @@ macro_rules! rgb_color {
     };
 }
 /* parse error: expected type */
-/* parse error: expected R_PAREN */
 /* parse error: expected R_ANGLE */
 /* parse error: expected COMMA */
 /* parse error: expected R_ANGLE */
 /* parse error: expected SEMICOLON */
-/* parse error: expected SEMICOLON */
-/* parse error: expected expression */
 pub fn new() {
-    let _ = 0as u32<<(8+8);
+    let _ = 0as u32<<8+8;
 }
-// MACRO_ITEMS@0..31
-//   FN@0..31
+// MACRO_ITEMS@0..29
+//   FN@0..29
 //     VISIBILITY@0..3
 //       PUB_KW@0..3 "pub"
 //     FN_KW@3..5 "fn"
@@ -845,45 +842,39 @@ pub fn new() {
 //     PARAM_LIST@8..10
 //       L_PAREN@8..9 "("
 //       R_PAREN@9..10 ")"
-//     BLOCK_EXPR@10..31
-//       STMT_LIST@10..31
+//     BLOCK_EXPR@10..29
+//       STMT_LIST@10..29
 //         L_CURLY@10..11 "{"
-//         LET_STMT@11..27
+//         LET_STMT@11..24
 //           LET_KW@11..14 "let"
 //           WILDCARD_PAT@14..15
 //             UNDERSCORE@14..15 "_"
 //           EQ@15..16 "="
-//           CAST_EXPR@16..27
+//           CAST_EXPR@16..24
 //             LITERAL@16..17
 //               INT_NUMBER@16..17 "0"
 //             AS_KW@17..19 "as"
-//             PATH_TYPE@19..27
-//               PATH@19..27
-//                 PATH_SEGMENT@19..27
+//             PATH_TYPE@19..24
+//               PATH@19..24
+//                 PATH_SEGMENT@19..24
 //                   NAME_REF@19..22
 //                     IDENT@19..22 "u32"
-//                   GENERIC_ARG_LIST@22..27
+//                   GENERIC_ARG_LIST@22..24
 //                     L_ANGLE@22..23 "<"
-//                     TYPE_ARG@23..27
-//                       DYN_TRAIT_TYPE@23..27
-//                         TYPE_BOUND_LIST@23..27
-//                           TYPE_BOUND@23..26
-//                             PATH_TYPE@23..26
-//                               PATH@23..26
-//                                 PATH_SEGMENT@23..26
-//                                   L_ANGLE@23..24 "<"
-//                                   PAREN_TYPE@24..26
-//                                     L_PAREN@24..25 "("
-//                                     ERROR@25..26
-//                                       INT_NUMBER@25..26 "8"
-//                           PLUS@26..27 "+"
-//         EXPR_STMT@27..28
-//           LITERAL@27..28
-//             INT_NUMBER@27..28 "8"
-//         ERROR@28..29
-//           R_PAREN@28..29 ")"
-//         SEMICOLON@29..30 ";"
-//         R_CURLY@30..31 "}"
+//                     TYPE_ARG@23..24
+//                       PATH_TYPE@23..24
+//                         PATH@23..24
+//                           PATH_SEGMENT@23..24
+//                             L_ANGLE@23..24 "<"
+//         EXPR_STMT@24..28
+//           BIN_EXPR@24..27
+//             LITERAL@24..25
+//               INT_NUMBER@24..25 "8"
+//             PLUS@25..26 "+"
+//             LITERAL@26..27
+//               INT_NUMBER@26..27 "8"
+//           SEMICOLON@27..28 ";"
+//         R_CURLY@28..29 "}"
 
 "#]],
     );
diff --git a/crates/hir_def/src/macro_expansion_tests/proc_macros.rs b/crates/hir_def/src/macro_expansion_tests/proc_macros.rs
index 81f58fa2ce..ef8dc3e3b0 100644
--- a/crates/hir_def/src/macro_expansion_tests/proc_macros.rs
+++ b/crates/hir_def/src/macro_expansion_tests/proc_macros.rs
@@ -33,7 +33,7 @@ fn derive_censoring() {
 //- proc_macros: derive_identity
 #[attr1]
 #[derive(Foo)]
-#[derive(proc_macros::DeriveIdentity)]
+#[derive(proc_macros::derive_identity)]
 #[derive(Bar)]
 #[attr2]
 struct S;
@@ -41,7 +41,7 @@ struct S;
         expect![[r##"
 #[attr1]
 #[derive(Foo)]
-#[derive(proc_macros::DeriveIdentity)]
+#[derive(proc_macros::derive_identity)]
 #[derive(Bar)]
 #[attr2]
 struct S;
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 2aa54fc33f..b6cec50038 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -3651,7 +3651,6 @@ use crate as foo$0;
 fn hover_attribute_in_macro() {
     check(
         r#"
-//- minicore:derive
 macro_rules! identity {
     ($struct:item) => {
         $struct
@@ -3682,7 +3681,6 @@ identity!{
 fn hover_derive_input() {
     check(
         r#"
-//- minicore:derive
 #[rustc_builtin_macro]
 pub macro Copy {}
 #[derive(Copy$0)]
@@ -3702,7 +3700,6 @@ struct Foo;
     );
     check(
         r#"
-//- minicore:derive
 mod foo {
     #[rustc_builtin_macro]
     pub macro Copy {}
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 9c92bd3e74..d9e1a05a03 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -128,7 +128,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="brace">}</span>
 
 <span class="comment documentation">/// ```</span>
-<span class="comment documentation">/// </span><span class="keyword injected">macro_rules</span><span class="punctuation injected">!</span><span class="none injected"> </span><span class="macro declaration injected">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="angle injected">&gt;</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span>
 <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
 <span class="comment documentation">/// ```</span>
 <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 1a10a78d24..05e6739830 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -43,6 +43,15 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
 <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
 
+<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
+<span class="keyword">macro</span> <span class="macro declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span>
+
+<span class="comment">// Needed for function consuming vs normal</span>
+<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">marker</span> <span class="brace">{</span>
+    <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span>
+    <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">Copy</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="brace">}</span>
+
 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="module attribute">proc_macros</span><span class="operator attribute">::</span><span class="builtin_attr attribute">identity</span><span class="attribute attribute">]</span>
 <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">ops</span> <span class="brace">{</span>
     <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span>
@@ -86,7 +95,7 @@ proc_macros::<span class="macro">mirror!</span> <span class="brace">{</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="macro attribute">derive</span><span class="parenthesis attribute">(</span><span class="macro attribute default_library library">Copy</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
+<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">derive</span><span class="parenthesis attribute">(</span><span class="macro attribute">Copy</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
 <span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="brace">{</span>
     <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
 <span class="brace">}</span>
@@ -126,7 +135,7 @@ proc_macros::<span class="macro">mirror!</span> <span class="brace">{</span>
     <span class="value_param callable">f</span><span class="parenthesis">(</span><span class="parenthesis">)</span>
 <span class="brace">}</span>
 
-<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="keyword">impl</span> <span class="trait default_library library">Copy</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 05158c169e..850de3908f 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -11,11 +11,19 @@ fn test_highlighting() {
     check_highlighting(
         r#"
 //- proc_macros: identity, mirror
-//- minicore: derive, copy
 //- /main.rs crate:main deps:foo
 use inner::{self as inner_mod};
 mod inner {}
 
+#[rustc_builtin_macro]
+macro Copy {}
+
+// Needed for function consuming vs normal
+pub mod marker {
+    #[lang = "copy"]
+    pub trait Copy {}
+}
+
 #[proc_macros::identity]
 pub mod ops {
     #[lang = "fn_once"]
@@ -707,7 +715,6 @@ pub mod module {
 }
 
 /// ```
-/// macro_rules! noop { ($expr:expr) => { $expr }}
 /// noop!(1);
 /// ```
 macro_rules! noop {
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index e30f98bcd1..43d30e84b3 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -1876,25 +1876,6 @@ fn handle() {
     )
 }
 
-#[test]
-fn doctest_replace_turbofish_with_explicit_type() {
-    check_doc_test(
-        "replace_turbofish_with_explicit_type",
-        r#####"
-fn make<T>() -> T { ) }
-fn main() {
-    let a = make$0::<i32>();
-}
-"#####,
-        r#####"
-fn make<T>() -> T { ) }
-fn main() {
-    let a: i32 = make();
-}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_sort_items() {
     check_doc_test(
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs
index f063a9638c..4028fc2242 100644
--- a/crates/ide_completion/src/tests.rs
+++ b/crates/ide_completion/src/tests.rs
@@ -20,7 +20,6 @@ mod record;
 mod type_pos;
 mod use_tree;
 mod visibility;
-mod flyimport;
 
 use std::mem;
 
@@ -38,7 +37,7 @@ use stdx::{format_to, trim_indent};
 use syntax::{AstNode, NodeOrToken, SyntaxElement};
 use test_utils::assert_eq_text;
 
-use crate::{CompletionConfig, CompletionItem, CompletionItemKind};
+use crate::{item::CompletionKind, CompletionConfig, CompletionItem};
 
 /// Lots of basic item definitions
 const BASE_ITEMS_FIXTURE: &str = r#"
@@ -78,28 +77,18 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
 };
 
 pub(crate) fn completion_list(ra_fixture: &str) -> String {
-    completion_list_with_config(TEST_CONFIG, ra_fixture, true)
+    completion_list_with_config(TEST_CONFIG, ra_fixture)
 }
 
-pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
-    completion_list_with_config(TEST_CONFIG, ra_fixture, false)
-}
-
-fn completion_list_with_config(
-    config: CompletionConfig,
-    ra_fixture: &str,
-    include_keywords: bool,
-) -> String {
+fn completion_list_with_config(config: CompletionConfig, ra_fixture: &str) -> String {
     // filter out all but one builtintype completion for smaller test outputs
     let items = get_all_items(config, ra_fixture);
     let mut bt_seen = false;
     let items = items
         .into_iter()
         .filter(|it| {
-            it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true)
+            it.completion_kind != CompletionKind::BuiltinType || !mem::replace(&mut bt_seen, true)
         })
-        .filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
-        .filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
         .collect();
     render_completion_list(items)
 }
@@ -115,22 +104,36 @@ pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
     (database, FilePosition { file_id, offset })
 }
 
-pub(crate) fn do_completion(code: &str, kind: CompletionItemKind) -> Vec<CompletionItem> {
+pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
     do_completion_with_config(TEST_CONFIG, code, kind)
 }
 
 pub(crate) fn do_completion_with_config(
     config: CompletionConfig,
     code: &str,
-    kind: CompletionItemKind,
+    kind: CompletionKind,
 ) -> Vec<CompletionItem> {
     get_all_items(config, code)
         .into_iter()
-        .filter(|c| c.kind() == kind)
+        .filter(|c| c.completion_kind == kind)
         .sorted_by(|l, r| l.label().cmp(r.label()))
         .collect()
 }
 
+pub(crate) fn filtered_completion_list(code: &str, kind: CompletionKind) -> String {
+    filtered_completion_list_with_config(TEST_CONFIG, code, kind)
+}
+
+pub(crate) fn filtered_completion_list_with_config(
+    config: CompletionConfig,
+    code: &str,
+    kind: CompletionKind,
+) -> String {
+    let kind_completions: Vec<CompletionItem> =
+        get_all_items(config, code).into_iter().filter(|c| c.completion_kind == kind).collect();
+    render_completion_list(kind_completions)
+}
+
 fn render_completion_list(completions: Vec<CompletionItem>) -> String {
     fn monospace_width(s: &str) -> usize {
         s.chars().count()
@@ -140,7 +143,7 @@ fn render_completion_list(completions: Vec<CompletionItem>) -> String {
     completions
         .into_iter()
         .map(|it| {
-            let tag = it.kind().tag();
+            let tag = it.kind().unwrap().tag();
             let var_name = format!("{} {}", tag, it.label());
             let mut buf = var_name;
             if let Some(detail) = it.detail() {
@@ -251,37 +254,3 @@ fn foo() {
 "#,
     );
 }
-
-#[test]
-fn no_completions_in_comments() {
-    cov_mark::check!(no_keyword_completion_in_comments);
-    assert_eq!(
-        completion_list(
-            r#"
-fn test() {
-let x = 2; // A comment$0
-}
-"#,
-        ),
-        String::new(),
-    );
-    assert_eq!(
-        completion_list(
-            r#"
-/*
-Some multi-line comment$0
-*/
-"#,
-        ),
-        String::new(),
-    );
-    assert_eq!(
-        completion_list(
-            r#"
-/// Some doc comment
-/// let test$0 = 1
-"#,
-        ),
-        String::new(),
-    );
-}
diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs
index 45979d4828..9f86fc50a2 100644
--- a/crates/ide_completion/src/tests/attribute.rs
+++ b/crates/ide_completion/src/tests/attribute.rs
@@ -640,45 +640,6 @@ mod derive {
             "#]],
         )
     }
-
-    #[test]
-    fn derive_flyimport() {
-        check_derive(
-            r#"
-//- proc_macros: derive_identity
-#[derive(der$0)] struct Test;
-"#,
-            expect![[r#"
-                at DeriveIdentity (use proc_macros::DeriveIdentity)
-            "#]],
-        );
-        check_derive(
-            r#"
-//- proc_macros: derive_identity
-use proc_macros::DeriveIdentity;
-#[derive(der$0)] struct Test;
-"#,
-            expect![[r#"
-                at DeriveIdentity
-            "#]],
-        );
-    }
-
-    #[test]
-    fn derive_flyimport_edit() {
-        check_edit(
-            "DeriveIdentity",
-            r#"
-//- proc_macros: derive_identity
-#[derive(der$0)] struct Test;
-"#,
-            r#"
-use proc_macros::DeriveIdentity;
-
-#[derive(DeriveIdentity)] struct Test;
-"#,
-        );
-    }
 }
 
 mod lint {
diff --git a/crates/ide_completion/src/tests/expression.rs b/crates/ide_completion/src/tests/expression.rs
index a634808734..9a42dd7b27 100644
--- a/crates/ide_completion/src/tests/expression.rs
+++ b/crates/ide_completion/src/tests/expression.rs
@@ -110,7 +110,7 @@ fn func(param0 @ (param1, param2): (i32, i32)) {
 }
 
 #[test]
-fn completes_all_the_things_in_fn_body() {
+fn completes_all_the_things() {
     cov_mark::check!(unqualified_skip_lifetime_completion);
     check(
         r#"
@@ -206,223 +206,6 @@ impl Unit {
     );
 }
 
-#[test]
-fn complete_in_block() {
-    check_empty(
-        r#"
-    fn foo() {
-        if true {
-            $0
-        }
-    }
-"#,
-        expect![[r#"
-            kw unsafe
-            kw fn
-            kw const
-            kw type
-            kw impl
-            kw extern
-            kw use
-            kw trait
-            kw static
-            kw mod
-            kw match
-            kw while
-            kw while let
-            kw loop
-            kw if
-            kw if let
-            kw for
-            kw true
-            kw false
-            kw let
-            kw return
-            sn pd
-            sn ppd
-            kw self
-            kw super
-            kw crate
-            fn foo()     fn()
-            bt u32
-        "#]],
-    )
-}
-
-#[test]
-fn complete_after_if_expr() {
-    check_empty(
-        r#"
-    fn foo() {
-        if true {}
-        $0
-    }
-"#,
-        expect![[r#"
-            kw unsafe
-            kw fn
-            kw const
-            kw type
-            kw impl
-            kw extern
-            kw use
-            kw trait
-            kw static
-            kw mod
-            kw match
-            kw while
-            kw while let
-            kw loop
-            kw if
-            kw if let
-            kw for
-            kw true
-            kw false
-            kw let
-            kw else
-            kw else if
-            kw return
-            sn pd
-            sn ppd
-            kw self
-            kw super
-            kw crate
-            fn foo()     fn()
-            bt u32
-        "#]],
-    )
-}
-
-#[test]
-fn complete_in_match_arm() {
-    check_empty(
-        r#"
-    fn foo() {
-        match () {
-            () => $0
-        }
-    }
-"#,
-        expect![[r#"
-            kw unsafe
-            kw match
-            kw while
-            kw while let
-            kw loop
-            kw if
-            kw if let
-            kw for
-            kw true
-            kw false
-            kw return
-            kw self
-            kw super
-            kw crate
-            fn foo()     fn()
-            bt u32
-        "#]],
-    )
-}
-
-#[test]
-fn completes_in_loop_ctx() {
-    check_empty(
-        r"fn my() { loop { $0 } }",
-        expect![[r#"
-            kw unsafe
-            kw fn
-            kw const
-            kw type
-            kw impl
-            kw extern
-            kw use
-            kw trait
-            kw static
-            kw mod
-            kw match
-            kw while
-            kw while let
-            kw loop
-            kw if
-            kw if let
-            kw for
-            kw true
-            kw false
-            kw let
-            kw continue
-            kw break
-            kw return
-            sn pd
-            sn ppd
-            kw self
-            kw super
-            kw crate
-            fn my()      fn()
-            bt u32
-        "#]],
-    );
-}
-
-#[test]
-fn completes_in_let_initializer() {
-    check_empty(
-        r#"fn main() { let _ = $0 }"#,
-        expect![[r#"
-            kw unsafe
-            kw match
-            kw while
-            kw while let
-            kw loop
-            kw if
-            kw if let
-            kw for
-            kw true
-            kw false
-            kw return
-            kw self
-            kw super
-            kw crate
-            fn main()    fn()
-            bt u32
-        "#]],
-    )
-}
-
-#[test]
-fn struct_initializer_field_expr() {
-    check_empty(
-        r#"
-struct Foo {
-    pub f: i32,
-}
-fn foo() {
-    Foo {
-        f: $0
-    }
-}
-"#,
-        expect![[r#"
-            kw unsafe
-            kw match
-            kw while
-            kw while let
-            kw loop
-            kw if
-            kw if let
-            kw for
-            kw true
-            kw false
-            kw return
-            kw self
-            kw super
-            kw crate
-            st Foo
-            fn foo()     fn()
-            bt u32
-        "#]],
-    );
-}
-
 #[test]
 fn shadowing_shows_single_completion() {
     cov_mark::check!(shadowing_shows_single_completion);
diff --git a/crates/ide_completion/src/tests/flyimport.rs b/crates/ide_completion/src/tests/flyimport.rs
deleted file mode 100644
index 201443e10c..0000000000
--- a/crates/ide_completion/src/tests/flyimport.rs
+++ /dev/null
@@ -1,1014 +0,0 @@
-use expect_test::{expect, Expect};
-
-use crate::tests::{check_edit, check_edit_with_config, TEST_CONFIG};
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let config = TEST_CONFIG;
-    let (db, position) = crate::tests::position(ra_fixture);
-    let ctx = crate::context::CompletionContext::new(&db, position, &config).unwrap();
-
-    let mut acc = crate::completions::Completions::default();
-    crate::completions::flyimport::import_on_the_fly(&mut acc, &ctx);
-
-    expect.assert_eq(&super::render_completion_list(Vec::from(acc)));
-}
-
-#[test]
-fn function_fuzzy_completion() {
-    check_edit(
-        "stdin",
-        r#"
-//- /lib.rs crate:dep
-pub mod io {
-    pub fn stdin() {}
-};
-
-//- /main.rs crate:main deps:dep
-fn main() {
-    stdi$0
-}
-"#,
-        r#"
-use dep::io::stdin;
-
-fn main() {
-    stdin()$0
-}
-"#,
-    );
-}
-
-#[test]
-fn macro_fuzzy_completion() {
-    check_edit(
-        "macro_with_curlies!",
-        r#"
-//- /lib.rs crate:dep
-/// Please call me as macro_with_curlies! {}
-#[macro_export]
-macro_rules! macro_with_curlies {
-    () => {}
-}
-
-//- /main.rs crate:main deps:dep
-fn main() {
-    curli$0
-}
-"#,
-        r#"
-use dep::macro_with_curlies;
-
-fn main() {
-    macro_with_curlies! {$0}
-}
-"#,
-    );
-}
-
-#[test]
-fn struct_fuzzy_completion() {
-    check_edit(
-        "ThirdStruct",
-        r#"
-//- /lib.rs crate:dep
-pub struct FirstStruct;
-pub mod some_module {
-    pub struct SecondStruct;
-    pub struct ThirdStruct;
-}
-
-//- /main.rs crate:main deps:dep
-use dep::{FirstStruct, some_module::SecondStruct};
-
-fn main() {
-    this$0
-}
-"#,
-        r#"
-use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
-
-fn main() {
-    ThirdStruct
-}
-"#,
-    );
-}
-
-#[test]
-fn short_paths_are_ignored() {
-    cov_mark::check!(ignore_short_input_for_path);
-
-    check(
-        r#"
-//- /lib.rs crate:dep
-pub struct FirstStruct;
-pub mod some_module {
-    pub struct SecondStruct;
-    pub struct ThirdStruct;
-}
-
-//- /main.rs crate:main deps:dep
-use dep::{FirstStruct, some_module::SecondStruct};
-
-fn main() {
-    t$0
-}
-"#,
-        expect![[r#""#]],
-    );
-}
-
-#[test]
-fn fuzzy_completions_come_in_specific_order() {
-    cov_mark::check!(certain_fuzzy_order_test);
-    check(
-        r#"
-//- /lib.rs crate:dep
-pub struct FirstStruct;
-pub mod some_module {
-    // already imported, omitted
-    pub struct SecondStruct;
-    // does not contain all letters from the query, omitted
-    pub struct UnrelatedOne;
-    // contains all letters from the query, but not in sequence, displayed last
-    pub struct ThiiiiiirdStruct;
-    // contains all letters from the query, but not in the beginning, displayed second
-    pub struct AfterThirdStruct;
-    // contains all letters from the query in the begginning, displayed first
-    pub struct ThirdStruct;
-}
-
-//- /main.rs crate:main deps:dep
-use dep::{FirstStruct, some_module::SecondStruct};
-
-fn main() {
-    hir$0
-}
-"#,
-        expect![[r#"
-                st ThirdStruct (use dep::some_module::ThirdStruct)
-                st AfterThirdStruct (use dep::some_module::AfterThirdStruct)
-                st ThiiiiiirdStruct (use dep::some_module::ThiiiiiirdStruct)
-            "#]],
-    );
-}
-
-#[test]
-fn trait_function_fuzzy_completion() {
-    let fixture = r#"
-        //- /lib.rs crate:dep
-        pub mod test_mod {
-            pub trait TestTrait {
-                const SPECIAL_CONST: u8;
-                type HumbleType;
-                fn weird_function();
-                fn random_method(&self);
-            }
-            pub struct TestStruct {}
-            impl TestTrait for TestStruct {
-                const SPECIAL_CONST: u8 = 42;
-                type HumbleType = ();
-                fn weird_function() {}
-                fn random_method(&self) {}
-            }
-        }
-
-        //- /main.rs crate:main deps:dep
-        fn main() {
-            dep::test_mod::TestStruct::wei$0
-        }
-        "#;
-
-    check(
-        fixture,
-        expect![[r#"
-                fn weird_function() (use dep::test_mod::TestTrait) fn()
-            "#]],
-    );
-
-    check_edit(
-        "weird_function",
-        fixture,
-        r#"
-use dep::test_mod::TestTrait;
-
-fn main() {
-    dep::test_mod::TestStruct::weird_function()$0
-}
-"#,
-    );
-}
-
-#[test]
-fn trait_const_fuzzy_completion() {
-    let fixture = r#"
-        //- /lib.rs crate:dep
-        pub mod test_mod {
-            pub trait TestTrait {
-                const SPECIAL_CONST: u8;
-                type HumbleType;
-                fn weird_function();
-                fn random_method(&self);
-            }
-            pub struct TestStruct {}
-            impl TestTrait for TestStruct {
-                const SPECIAL_CONST: u8 = 42;
-                type HumbleType = ();
-                fn weird_function() {}
-                fn random_method(&self) {}
-            }
-        }
-
-        //- /main.rs crate:main deps:dep
-        fn main() {
-            dep::test_mod::TestStruct::spe$0
-        }
-        "#;
-
-    check(
-        fixture,
-        expect![[r#"
-            ct SPECIAL_CONST (use dep::test_mod::TestTrait)
-        "#]],
-    );
-
-    check_edit(
-        "SPECIAL_CONST",
-        fixture,
-        r#"
-use dep::test_mod::TestTrait;
-
-fn main() {
-    dep::test_mod::TestStruct::SPECIAL_CONST
-}
-"#,
-    );
-}
-
-#[test]
-fn trait_method_fuzzy_completion() {
-    let fixture = r#"
-        //- /lib.rs crate:dep
-        pub mod test_mod {
-            pub trait TestTrait {
-                const SPECIAL_CONST: u8;
-                type HumbleType;
-                fn weird_function();
-                fn random_method(&self);
-            }
-            pub struct TestStruct {}
-            impl TestTrait for TestStruct {
-                const SPECIAL_CONST: u8 = 42;
-                type HumbleType = ();
-                fn weird_function() {}
-                fn random_method(&self) {}
-            }
-        }
-
-        //- /main.rs crate:main deps:dep
-        fn main() {
-            let test_struct = dep::test_mod::TestStruct {};
-            test_struct.ran$0
-        }
-        "#;
-
-    check(
-        fixture,
-        expect![[r#"
-                me random_method() (use dep::test_mod::TestTrait) fn(&self)
-            "#]],
-    );
-
-    check_edit(
-        "random_method",
-        fixture,
-        r#"
-use dep::test_mod::TestTrait;
-
-fn main() {
-    let test_struct = dep::test_mod::TestStruct {};
-    test_struct.random_method()$0
-}
-"#,
-    );
-}
-
-#[test]
-fn no_trait_type_fuzzy_completion() {
-    check(
-        r#"
-//- /lib.rs crate:dep
-pub mod test_mod {
-    pub trait TestTrait {
-        const SPECIAL_CONST: u8;
-        type HumbleType;
-        fn weird_function();
-        fn random_method(&self);
-    }
-    pub struct TestStruct {}
-    impl TestTrait for TestStruct {
-        const SPECIAL_CONST: u8 = 42;
-        type HumbleType = ();
-        fn weird_function() {}
-        fn random_method(&self) {}
-    }
-}
-
-//- /main.rs crate:main deps:dep
-fn main() {
-    dep::test_mod::TestStruct::hum$0
-}
-"#,
-        expect![[r#""#]],
-    );
-}
-
-#[test]
-fn does_not_propose_names_in_scope() {
-    check(
-        r#"
-//- /lib.rs crate:dep
-pub mod test_mod {
-    pub trait TestTrait {
-        const SPECIAL_CONST: u8;
-        type HumbleType;
-        fn weird_function();
-        fn random_method(&self);
-    }
-    pub struct TestStruct {}
-    impl TestTrait for TestStruct {
-        const SPECIAL_CONST: u8 = 42;
-        type HumbleType = ();
-        fn weird_function() {}
-        fn random_method(&self) {}
-    }
-}
-
-//- /main.rs crate:main deps:dep
-use dep::test_mod::TestStruct;
-fn main() {
-    TestSt$0
-}
-"#,
-        expect![[r#""#]],
-    );
-}
-
-#[test]
-fn does_not_propose_traits_in_scope() {
-    check(
-        r#"
-//- /lib.rs crate:dep
-pub mod test_mod {
-    pub trait TestTrait {
-        const SPECIAL_CONST: u8;
-        type HumbleType;
-        fn weird_function();
-        fn random_method(&self);
-    }
-    pub struct TestStruct {}
-    impl TestTrait for TestStruct {
-        const SPECIAL_CONST: u8 = 42;
-        type HumbleType = ();
-        fn weird_function() {}
-        fn random_method(&self) {}
-    }
-}
-
-//- /main.rs crate:main deps:dep
-use dep::test_mod::{TestStruct, TestTrait};
-fn main() {
-    dep::test_mod::TestStruct::hum$0
-}
-"#,
-        expect![[r#""#]],
-    );
-}
-
-#[test]
-fn blanket_trait_impl_import() {
-    check_edit(
-        "another_function",
-        r#"
-//- /lib.rs crate:dep
-pub mod test_mod {
-    pub struct TestStruct {}
-    pub trait TestTrait {
-        fn another_function();
-    }
-    impl<T> TestTrait for T {
-        fn another_function() {}
-    }
-}
-
-//- /main.rs crate:main deps:dep
-fn main() {
-    dep::test_mod::TestStruct::ano$0
-}
-"#,
-        r#"
-use dep::test_mod::TestTrait;
-
-fn main() {
-    dep::test_mod::TestStruct::another_function()$0
-}
-"#,
-    );
-}
-
-#[test]
-fn zero_input_deprecated_assoc_item_completion() {
-    check(
-        r#"
-//- /lib.rs crate:dep
-pub mod test_mod {
-    #[deprecated]
-    pub trait TestTrait {
-        const SPECIAL_CONST: u8;
-        type HumbleType;
-        fn weird_function();
-        fn random_method(&self);
-    }
-    pub struct TestStruct {}
-    impl TestTrait for TestStruct {
-        const SPECIAL_CONST: u8 = 42;
-        type HumbleType = ();
-        fn weird_function() {}
-        fn random_method(&self) {}
-    }
-}
-
-//- /main.rs crate:main deps:dep
-fn main() {
-    let test_struct = dep::test_mod::TestStruct {};
-    test_struct.$0
-}
-        "#,
-        expect![[r#"
-                me random_method() (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
-            "#]],
-    );
-
-    check(
-        r#"
-//- /lib.rs crate:dep
-pub mod test_mod {
-    #[deprecated]
-    pub trait TestTrait {
-        const SPECIAL_CONST: u8;
-        type HumbleType;
-        fn weird_function();
-        fn random_method(&self);
-    }
-    pub struct TestStruct {}
-    impl TestTrait for TestStruct {
-        const SPECIAL_CONST: u8 = 42;
-        type HumbleType = ();
-        fn weird_function() {}
-        fn random_method(&self) {}
-    }
-}
-
-//- /main.rs crate:main deps:dep
-fn main() {
-    dep::test_mod::TestStruct::$0
-}
-"#,
-        expect![[r#"
-                fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
-                ct SPECIAL_CONST (use dep::test_mod::TestTrait) DEPRECATED
-            "#]],
-    );
-}
-
-#[test]
-fn no_completions_in_use_statements() {
-    check(
-        r#"
-//- /lib.rs crate:dep
-pub mod io {
-    pub fn stdin() {}
-};
-
-//- /main.rs crate:main deps:dep
-use stdi$0
-
-fn main() {}
-"#,
-        expect![[]],
-    );
-}
-
-#[test]
-fn prefix_config_usage() {
-    let fixture = r#"
-mod foo {
-    pub mod bar {
-        pub struct Item;
-    }
-}
-
-use crate::foo::bar;
-
-fn main() {
-    Ite$0
-}"#;
-    let mut config = TEST_CONFIG;
-
-    config.insert_use.prefix_kind = hir::PrefixKind::ByCrate;
-    check_edit_with_config(
-        config.clone(),
-        "Item",
-        fixture,
-        r#"
-mod foo {
-    pub mod bar {
-        pub struct Item;
-    }
-}
-
-use crate::foo::bar::{self, Item};
-
-fn main() {
-    Item
-}"#,
-    );
-
-    config.insert_use.prefix_kind = hir::PrefixKind::BySelf;
-    check_edit_with_config(
-        config.clone(),
-        "Item",
-        fixture,
-        r#"
-mod foo {
-    pub mod bar {
-        pub struct Item;
-    }
-}
-
-use crate::foo::bar;
-
-use self::foo::bar::Item;
-
-fn main() {
-    Item
-}"#,
-    );
-
-    config.insert_use.prefix_kind = hir::PrefixKind::Plain;
-    check_edit_with_config(
-        config,
-        "Item",
-        fixture,
-        r#"
-mod foo {
-    pub mod bar {
-        pub struct Item;
-    }
-}
-
-use foo::bar::Item;
-
-use crate::foo::bar;
-
-fn main() {
-    Item
-}"#,
-    );
-}
-
-#[test]
-fn unresolved_qualifier() {
-    let fixture = r#"
-mod foo {
-    pub mod bar {
-        pub mod baz {
-            pub struct Item;
-        }
-    }
-}
-
-fn main() {
-    bar::baz::Ite$0
-}"#;
-
-    check(
-        fixture,
-        expect![[r#"
-        st Item (use foo::bar::baz::Item)
-        "#]],
-    );
-
-    check_edit(
-        "Item",
-        fixture,
-        r#"
-        use foo::bar;
-
-        mod foo {
-            pub mod bar {
-                pub mod baz {
-                    pub struct Item;
-                }
-            }
-        }
-
-        fn main() {
-            bar::baz::Item
-        }"#,
-    );
-}
-
-#[test]
-fn unresolved_assoc_item_container() {
-    let fixture = r#"
-mod foo {
-    pub struct Item;
-
-    impl Item {
-        pub const TEST_ASSOC: usize = 3;
-    }
-}
-
-fn main() {
-    Item::TEST_A$0
-}"#;
-
-    check(
-        fixture,
-        expect![[r#"
-        ct TEST_ASSOC (use foo::Item)
-        "#]],
-    );
-
-    check_edit(
-        "TEST_ASSOC",
-        fixture,
-        r#"
-use foo::Item;
-
-mod foo {
-    pub struct Item;
-
-    impl Item {
-        pub const TEST_ASSOC: usize = 3;
-    }
-}
-
-fn main() {
-    Item::TEST_ASSOC
-}"#,
-    );
-}
-
-#[test]
-fn unresolved_assoc_item_container_with_path() {
-    let fixture = r#"
-mod foo {
-    pub mod bar {
-        pub struct Item;
-
-        impl Item {
-            pub const TEST_ASSOC: usize = 3;
-        }
-    }
-}
-
-fn main() {
-    bar::Item::TEST_A$0
-}"#;
-
-    check(
-        fixture,
-        expect![[r#"
-        ct TEST_ASSOC (use foo::bar::Item)
-    "#]],
-    );
-
-    check_edit(
-        "TEST_ASSOC",
-        fixture,
-        r#"
-use foo::bar;
-
-mod foo {
-    pub mod bar {
-        pub struct Item;
-
-        impl Item {
-            pub const TEST_ASSOC: usize = 3;
-        }
-    }
-}
-
-fn main() {
-    bar::Item::TEST_ASSOC
-}"#,
-    );
-}
-
-#[test]
-fn fuzzy_unresolved_path() {
-    check(
-        r#"
-mod foo {
-    pub mod bar {
-        pub struct Item;
-
-        impl Item {
-            pub const TEST_ASSOC: usize = 3;
-        }
-    }
-}
-
-fn main() {
-    bar::ASS$0
-}"#,
-        expect![[]],
-    )
-}
-
-#[test]
-fn unqualified_assoc_items_are_omitted() {
-    check(
-        r#"
-mod something {
-    pub trait BaseTrait {
-        fn test_function() -> i32;
-    }
-
-    pub struct Item1;
-    pub struct Item2;
-
-    impl BaseTrait for Item1 {
-        fn test_function() -> i32 {
-            1
-        }
-    }
-
-    impl BaseTrait for Item2 {
-        fn test_function() -> i32 {
-            2
-        }
-    }
-}
-
-fn main() {
-    test_f$0
-}"#,
-        expect![[]],
-    )
-}
-
-#[test]
-fn case_matters() {
-    check(
-        r#"
-mod foo {
-    pub const TEST_CONST: usize = 3;
-    pub fn test_function() -> i32 {
-        4
-    }
-}
-
-fn main() {
-    TE$0
-}"#,
-        expect![[r#"
-        ct TEST_CONST (use foo::TEST_CONST)
-    "#]],
-    );
-
-    check(
-        r#"
-mod foo {
-    pub const TEST_CONST: usize = 3;
-    pub fn test_function() -> i32 {
-        4
-    }
-}
-
-fn main() {
-    te$0
-}"#,
-        expect![[r#"
-        ct TEST_CONST (use foo::TEST_CONST)
-        fn test_function() (use foo::test_function) fn() -> i32
-    "#]],
-    );
-
-    check(
-        r#"
-mod foo {
-    pub const TEST_CONST: usize = 3;
-    pub fn test_function() -> i32 {
-        4
-    }
-}
-
-fn main() {
-    Te$0
-}"#,
-        expect![[]],
-    );
-}
-
-#[test]
-fn no_fuzzy_during_fields_of_record_lit_syntax() {
-    check(
-        r#"
-mod m {
-    pub fn some_fn() -> i32 {
-        42
-    }
-}
-struct Foo {
-    some_field: i32,
-}
-fn main() {
-    let _ = Foo { so$0 };
-}
-"#,
-        expect![[]],
-    );
-}
-
-#[test]
-fn fuzzy_after_fields_of_record_lit_syntax() {
-    check(
-        r#"
-mod m {
-    pub fn some_fn() -> i32 {
-        42
-    }
-}
-struct Foo {
-    some_field: i32,
-}
-fn main() {
-    let _ = Foo { some_field: so$0 };
-}
-"#,
-        expect![[r#"
-                fn some_fn() (use m::some_fn) fn() -> i32
-            "#]],
-    );
-}
-
-#[test]
-fn no_flyimports_in_traits_and_impl_declarations() {
-    check(
-        r#"
-mod m {
-    pub fn some_fn() -> i32 {
-        42
-    }
-}
-trait Foo {
-    som$0
-}
-"#,
-        expect![[r#""#]],
-    );
-
-    check(
-        r#"
-mod m {
-    pub fn some_fn() -> i32 {
-        42
-    }
-}
-struct Foo;
-impl Foo {
-    som$0
-}
-"#,
-        expect![[r#""#]],
-    );
-
-    check(
-        r#"
-mod m {
-    pub fn some_fn() -> i32 {
-        42
-    }
-}
-struct Foo;
-trait Bar {}
-impl Bar for Foo {
-    som$0
-}
-"#,
-        expect![[r#""#]],
-    );
-}
-
-#[test]
-fn no_inherent_candidates_proposed() {
-    check(
-        r#"
-mod baz {
-    pub trait DefDatabase {
-        fn method1(&self);
-    }
-    pub trait HirDatabase: DefDatabase {
-        fn method2(&self);
-    }
-}
-
-mod bar {
-    fn test(db: &dyn crate::baz::HirDatabase) {
-        db.metho$0
-    }
-}
-            "#,
-        expect![[r#""#]],
-    );
-}
-
-#[test]
-fn respects_doc_hidden() {
-    check(
-        r#"
-//- /lib.rs crate:lib deps:dep
-fn f() {
-    ().fro$0
-}
-
-//- /dep.rs crate:dep
-#[doc(hidden)]
-pub trait Private {
-    fn frob(&self) {}
-}
-
-impl<T> Private for T {}
-            "#,
-        expect![[r#""#]],
-    );
-    check(
-        r#"
-//- /lib.rs crate:lib deps:dep
-fn f() {
-    ().fro$0
-}
-
-//- /dep.rs crate:dep
-pub trait Private {
-    #[doc(hidden)]
-    fn frob(&self) {}
-}
-
-impl<T> Private for T {}
-            "#,
-        expect![[r#""#]],
-    );
-}
-
-#[test]
-fn regression_9760() {
-    check(
-        r#"
-struct Struct;
-fn main() {}
-
-mod mud {
-    fn func() {
-        let struct_instance = Stru$0
-    }
-}
-"#,
-        expect![[r#"
-                st Struct (use crate::Struct)
-            "#]],
-    );
-}
-
-#[test]
-fn flyimport_pattern() {
-    check(
-        r#"
-mod module {
-    pub struct Struct;
-}
-fn function() {
-    let Str$0
-}
-"#,
-        expect![[r#"
-                st Struct (use module::Struct)
-            "#]],
-    );
-}
-
-#[test]
-fn flyimport_rename() {
-    check(
-        r#"
-mod module {
-    pub struct Struct;
-}
-use self as Str$0;
-    "#,
-        expect![[r#""#]],
-    );
-}
diff --git a/crates/ide_completion/src/tests/record.rs b/crates/ide_completion/src/tests/record.rs
index e09e99aad5..30b1f2c1c9 100644
--- a/crates/ide_completion/src/tests/record.rs
+++ b/crates/ide_completion/src/tests/record.rs
@@ -9,7 +9,6 @@ fn check(ra_fixture: &str, expect: Expect) {
 
 #[test]
 fn without_default_impl() {
-    cov_mark::check!(no_keyword_completion_in_record_lit);
     check(
         r#"
 struct Struct { foo: u32, bar: usize }
diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 5debb9fb3d..9be9f3afea 100644
--- a/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -313,7 +313,6 @@ fn check_dbg(path: &Path, text: &str) {
         "handlers/remove_dbg.rs",
         // We have .dbg postfix
         "ide_completion/src/completions/postfix.rs",
-        "ide_completion/src/completions/keyword.rs",
         "ide_completion/src/tests/proc_macros.rs",
         // The documentation in string literals may contain anything for its own purposes
         "ide_completion/src/lib.rs",
diff --git a/crates/syntax/src/tests/ast_src.rs b/crates/syntax/src/tests/ast_src.rs
index c0f1d5ef56..2344fc59d1 100644
--- a/crates/syntax/src/tests/ast_src.rs
+++ b/crates/syntax/src/tests/ast_src.rs
@@ -72,7 +72,16 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
     ],
     contextual_keywords: &["auto", "default", "existential", "union", "raw", "macro_rules"],
     literals: &["INT_NUMBER", "FLOAT_NUMBER", "CHAR", "BYTE", "STRING", "BYTE_STRING"],
-    tokens: &["ERROR", "IDENT", "WHITESPACE", "LIFETIME_IDENT", "COMMENT", "SHEBANG"],
+    tokens: &[
+        "ERROR",
+        "IDENT",
+        "WHITESPACE",
+        "LIFETIME_IDENT",
+        "COMMENT",
+        "SHEBANG",
+        "L_DOLLAR",
+        "R_DOLLAR",
+    ],
     nodes: &[
         "SOURCE_FILE",
         "STRUCT",
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index 36fedd2f0b..a1a96581b4 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -560,7 +560,7 @@ impl Field {
 
 fn lower(grammar: &Grammar) -> AstSrc {
     let mut res = AstSrc {
-        tokens: "Whitespace Comment String ByteString IntNumber FloatNumber Ident"
+        tokens: "Whitespace Comment String ByteString IntNumber FloatNumber"
             .split_ascii_whitespace()
             .map(|it| it.to_string())
             .collect::<Vec<_>>(),