]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide_completion/src/render.rs
fix: Do not complete `Drop::drop`, complete `std::mem::drop` instead
[rust.git] / crates / ide_completion / src / render.rs
index 6585b1cc8ae02dfdf13bd2875d89e2c6f72ff761..4fa5aa04dead5c9256e2c71b9c623a60eebaaf45 100644 (file)
@@ -7,21 +7,22 @@
 pub(crate) mod const_;
 pub(crate) mod pattern;
 pub(crate) mod type_alias;
+pub(crate) mod struct_literal;
 
 mod builder_ext;
 
-use hir::{AsAssocItem, HasAttrs, HirDisplay};
+use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
 use ide_db::{
     helpers::{item_name, SnippetCap},
     RootDatabase, SymbolKind,
 };
-use syntax::TextRange;
+use syntax::{SmolStr, SyntaxKind, TextRange};
 
 use crate::{
     context::{PathCompletionContext, PathKind},
     item::{CompletionRelevanceTypeMatch, ImportEdit},
     render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
-    CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
+    CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
 };
 /// Interface for data and methods required for items rendering.
 #[derive(Debug)]
@@ -46,8 +47,8 @@ fn source_range(&self) -> TextRange {
         self.completion.source_range()
     }
 
-    fn is_deprecated(&self, node: impl HasAttrs) -> bool {
-        let attrs = node.attrs(self.db());
+    fn is_deprecated(&self, def: impl HasAttrs) -> bool {
+        let attrs = def.attrs(self.db());
         attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists()
     }
 
@@ -70,8 +71,9 @@ fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool {
                 .unwrap_or(false)
     }
 
-    fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> {
-        node.docs(self.db())
+    // FIXME: remove this
+    fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
+        def.docs(self.db())
     }
 }
 
@@ -82,22 +84,25 @@ pub(crate) fn render_field(
     ty: &hir::Type,
 ) -> CompletionItem {
     let is_deprecated = ctx.is_deprecated(field);
-    let name = field.name(ctx.db()).to_string();
+    let name = field.name(ctx.db()).to_smol_str();
     let mut item = CompletionItem::new(
-        CompletionKind::Reference,
+        SymbolKind::Field,
         ctx.source_range(),
-        receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
+        receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name).into()),
     );
     item.set_relevance(CompletionRelevance {
         type_match: compute_type_match(ctx.completion, ty),
-        exact_name_match: compute_exact_name_match(ctx.completion, &name),
+        exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
         ..CompletionRelevance::default()
     });
-    item.kind(SymbolKind::Field)
-        .detail(ty.display(ctx.db()).to_string())
+    item.detail(ty.display(ctx.db()).to_string())
         .set_documentation(field.docs(ctx.db()))
         .set_deprecated(is_deprecated)
-        .lookup_by(name);
+        .lookup_by(name.clone());
+    let is_keyword = SyntaxKind::from_keyword(name.as_str()).is_some();
+    if is_keyword && !matches!(name.as_str(), "self" | "crate" | "super" | "Self") {
+        item.insert_text(format!("r#{}", name));
+    }
     if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) {
         // FIXME
         // For now we don't properly calculate the edits for ref match
@@ -113,20 +118,18 @@ pub(crate) fn render_tuple_field(
     ty: &hir::Type,
 ) -> CompletionItem {
     let mut item = CompletionItem::new(
-        CompletionKind::Reference,
+        SymbolKind::Field,
         ctx.source_range(),
         receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
     );
-    item.kind(SymbolKind::Field)
-        .detail(ty.display(ctx.db()).to_string())
-        .lookup_by(field.to_string());
+    item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string());
     item.build()
 }
 
 pub(crate) fn render_resolution(
     ctx: RenderContext<'_>,
     local_name: hir::Name,
-    resolution: &hir::ScopeDef,
+    resolution: ScopeDef,
 ) -> Option<CompletionItem> {
     render_resolution_(ctx, local_name, None, resolution)
 }
@@ -135,89 +138,77 @@ pub(crate) fn render_resolution_with_import(
     ctx: RenderContext<'_>,
     import_edit: ImportEdit,
 ) -> Option<CompletionItem> {
-    let resolution = hir::ScopeDef::from(import_edit.import.original_item);
+    let resolution = ScopeDef::from(import_edit.import.original_item);
     let local_name = match resolution {
-        hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
-        hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
-        hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
+        ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
+        ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
+        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).map(|mut item| {
-        item.completion_kind = CompletionKind::Magic;
-        item
-    })
+    render_resolution_(ctx, local_name, Some(import_edit), resolution)
 }
 
 fn render_resolution_(
     ctx: RenderContext<'_>,
     local_name: hir::Name,
     import_to_add: Option<ImportEdit>,
-    resolution: &hir::ScopeDef,
+    resolution: ScopeDef,
 ) -> Option<CompletionItem> {
     let _p = profile::span("render_resolution");
     use hir::ModuleDef::*;
 
-    let completion_kind = match resolution {
-        hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
-        _ => CompletionKind::Reference,
-    };
+    let db = ctx.db();
 
     let kind = match resolution {
-        hir::ScopeDef::ModuleDef(Function(func)) => {
-            return render_fn(ctx, import_to_add, Some(local_name), *func);
+        ScopeDef::ModuleDef(Function(func)) => {
+            return Some(render_fn(ctx, import_to_add, Some(local_name), func));
         }
-        hir::ScopeDef::ModuleDef(Variant(_)) if ctx.completion.is_pat_or_const.is_some() => {
-            CompletionItemKind::SymbolKind(SymbolKind::Variant)
+        ScopeDef::ModuleDef(Variant(var)) if ctx.completion.pattern_ctx.is_none() => {
+            return Some(render_variant(ctx, import_to_add, Some(local_name), var, None));
         }
-        hir::ScopeDef::ModuleDef(Variant(var)) => {
-            let item = render_variant(ctx, import_to_add, Some(local_name), *var, None);
-            return Some(item);
-        }
-        hir::ScopeDef::MacroDef(mac) => {
-            let item = render_macro(ctx, import_to_add, local_name, *mac);
-            return item;
+        ScopeDef::MacroDef(mac) => return render_macro(ctx, import_to_add, local_name, mac),
+        ScopeDef::Unknown => {
+            let mut item = CompletionItem::new(
+                CompletionItemKind::UnresolvedReference,
+                ctx.source_range(),
+                local_name.to_smol_str(),
+            );
+            if let Some(import_to_add) = import_to_add {
+                item.add_import(import_to_add);
+            }
+            return Some(item.build());
         }
 
-        hir::ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
-        hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
+        ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant),
+        ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
+        ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
             hir::Adt::Struct(_) => SymbolKind::Struct,
             hir::Adt::Union(_) => SymbolKind::Union,
             hir::Adt::Enum(_) => SymbolKind::Enum,
         }),
-        hir::ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
-        hir::ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
-        hir::ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
-        hir::ScopeDef::ModuleDef(TypeAlias(..)) => {
-            CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
-        }
-        hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
-        hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
+        ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
+        ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
+        ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
+        ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::SymbolKind(SymbolKind::TypeAlias),
+        ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
+        ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
             hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
             hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
             hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
         }),
-        hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
-        hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
-        hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => {
+        ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
+        ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
+        ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {
             CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
         }
-        hir::ScopeDef::Unknown => {
-            let mut item = CompletionItem::new(
-                CompletionKind::Reference,
-                ctx.source_range(),
-                local_name.to_string(),
-            );
-            item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add);
-            return Some(item.build());
-        }
     };
 
-    let local_name = local_name.to_string();
-    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());
+    let local_name = local_name.to_smol_str();
+    let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.clone());
+    if let ScopeDef::Local(local) = resolution {
+        let ty = local.ty(db);
         if !ty.is_unknown() {
-            item.detail(ty.display(ctx.db()).to_string());
+            item.detail(ty.display(db).to_string());
         }
 
         item.set_relevance(CompletionRelevance {
@@ -233,52 +224,54 @@ fn render_resolution_(
     };
 
     // Add `<>` for generic types
-    if matches!(
+    let type_path_no_ty_args = matches!(
         ctx.completion.path_context,
         Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. })
-    ) && ctx.completion.config.add_call_parenthesis
-    {
+    ) && ctx.completion.config.add_call_parenthesis;
+    if type_path_no_ty_args {
         if let Some(cap) = ctx.snippet_cap() {
             let has_non_default_type_params = match resolution {
-                hir::ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db()),
-                hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db()),
+                ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(db),
+                ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(db),
                 _ => false,
             };
             if has_non_default_type_params {
                 cov_mark::hit!(inserts_angle_brackets_for_generics);
                 item.lookup_by(local_name.clone())
-                    .label(format!("{}<…>", local_name))
+                    .label(SmolStr::from_iter([&local_name, "<…>"]))
                     .insert_snippet(cap, format!("{}<$0>", local_name));
             }
         }
     }
-    item.kind(kind)
-        .add_import(import_to_add)
-        .set_documentation(scope_def_docs(ctx.db(), resolution))
+    item.set_documentation(scope_def_docs(db, resolution))
         .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
+
+    if let Some(import_to_add) = import_to_add {
+        item.add_import(import_to_add);
+    }
     Some(item.build())
 }
 
-fn scope_def_docs(db: &RootDatabase, resolution: &hir::ScopeDef) -> Option<hir::Documentation> {
+fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> {
     use hir::ModuleDef::*;
     match resolution {
-        hir::ScopeDef::ModuleDef(Module(it)) => it.docs(db),
-        hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
-        hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
-        hir::ScopeDef::ModuleDef(Const(it)) => it.docs(db),
-        hir::ScopeDef::ModuleDef(Static(it)) => it.docs(db),
-        hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
-        hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
+        ScopeDef::ModuleDef(Module(it)) => it.docs(db),
+        ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
+        ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
+        ScopeDef::ModuleDef(Const(it)) => it.docs(db),
+        ScopeDef::ModuleDef(Static(it)) => it.docs(db),
+        ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
+        ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
         _ => None,
     }
 }
 
-fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: &hir::ScopeDef) -> bool {
+fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> bool {
     match resolution {
-        hir::ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(*it),
-        hir::ScopeDef::MacroDef(it) => ctx.is_deprecated(*it),
-        hir::ScopeDef::GenericParam(it) => ctx.is_deprecated(*it),
-        hir::ScopeDef::AdtSelfType(it) => ctx.is_deprecated(*it),
+        ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(it),
+        ScopeDef::MacroDef(it) => ctx.is_deprecated(it),
+        ScopeDef::GenericParam(it) => ctx.is_deprecated(it),
+        ScopeDef::AdtSelfType(it) => ctx.is_deprecated(it),
         _ => false,
     }
 }
@@ -333,37 +326,54 @@ 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},
-        CompletionKind, CompletionRelevance,
+        CompletionItem, CompletionItemKind, CompletionRelevance,
     };
 
     #[track_caller]
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = do_completion(ra_fixture, CompletionKind::Reference);
+    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_relevance(ra_fixture: &str, expect: Expect) {
-        check_relevance_for_kinds(&[CompletionKind::Reference], ra_fixture, expect)
+    fn check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
+        let actual: Vec<_> =
+            kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect();
+        expect.assert_debug_eq(&actual);
     }
 
     #[track_caller]
-    fn check_relevance_for_kinds(kinds: &[CompletionKind], ra_fixture: &str, expect: Expect) {
+    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.completion_kind));
+        actual.retain(|it| kinds.contains(&it.kind()));
         actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
+        check_relevance_(actual, expect);
+    }
 
+    #[track_caller]
+    fn check_relevance(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.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().unwrap().tag();
+                let tag = it.kind().tag();
                 let relevance = display_relevance(it.relevance());
                 items.push(format!("{} {} {}\n", tag, it.label(), relevance));
 
@@ -407,6 +417,7 @@ enum Foo { Foo { x: i32, y: i32 } }
 
 fn main() { Foo::Fo$0 }
 "#,
+            SymbolKind::Variant,
             expect![[r#"
                 [
                     CompletionItem {
@@ -417,7 +428,7 @@ fn main() { Foo::Fo$0 }
                         kind: SymbolKind(
                             Variant,
                         ),
-                        detail: "{ x: i32, y: i32 }",
+                        detail: "{x: i32, y: i32}",
                     },
                 ]
             "#]],
@@ -432,6 +443,7 @@ enum Foo { Foo (i32, i32) }
 
 fn main() { Foo::Fo$0 }
 "#,
+            SymbolKind::Variant,
             expect![[r#"
                 [
                     CompletionItem {
@@ -459,6 +471,7 @@ fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
 
 fn main() { fo$0 }
 "#,
+            SymbolKind::Function,
             expect![[r#"
                 [
                     CompletionItem {
@@ -497,6 +510,7 @@ enum Foo { Foo }
 
 fn main() { Foo::Fo$0 }
 "#,
+            SymbolKind::Variant,
             expect![[r#"
                 [
                     CompletionItem {
@@ -516,15 +530,40 @@ fn main() { Foo::Fo$0 }
 
     #[test]
     fn lookup_enums_by_two_qualifiers() {
-        check(
+        check_kinds(
             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,
@@ -545,15 +584,6 @@ 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,
@@ -573,17 +603,6 @@ 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()",
-                    },
                 ]
             "#]],
         )
@@ -600,6 +619,7 @@ fn something_else_deprecated() {}
 
 fn main() { som$0 }
 "#,
+            SymbolKind::Function,
             expect![[r#"
                 [
                     CompletionItem {
@@ -646,6 +666,7 @@ fn main() { som$0 }
 struct A { #[deprecated] the_field: u32 }
 fn foo() { A { the$0 } }
 "#,
+            SymbolKind::Field,
             expect![[r#"
                 [
                     CompletionItem {
@@ -674,7 +695,7 @@ fn foo() { A { the$0 } }
 
     #[test]
     fn renders_docs() {
-        check(
+        check_kinds(
             r#"
 struct S {
     /// Field docs
@@ -684,6 +705,7 @@ impl S {
     /// Method docs
     fn bar(self) { self.$0 }
 }"#,
+            &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
             expect![[r#"
                 [
                     CompletionItem {
@@ -715,7 +737,7 @@ fn bar(self) { self.$0 }
             "#]],
         );
 
-        check(
+        check_kinds(
             r#"
 use self::my$0;
 
@@ -729,18 +751,23 @@ enum E {
 }
 use self::E::*;
 "#,
+            &[
+                CompletionItemKind::SymbolKind(SymbolKind::Module),
+                CompletionItemKind::SymbolKind(SymbolKind::Variant),
+                CompletionItemKind::SymbolKind(SymbolKind::Enum),
+            ],
             expect![[r#"
                 [
                     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",
                         ),
                     },
                     CompletionItem {
@@ -757,15 +784,15 @@ enum E {
                         ),
                     },
                     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",
                         ),
                     },
                 ]
@@ -784,6 +811,7 @@ fn the_method(&self) { }
 }
 fn foo(s: S) { s.$0 }
 "#,
+            CompletionItemKind::Method,
             expect![[r#"
                 [
                     CompletionItem {
@@ -820,6 +848,23 @@ struct ManualVtable { f: fn(u8, u8) }
 fn main() -> ManualVtable {
     ManualVtable { f: foo }
 }
+"#,
+        );
+        check_edit(
+            "type",
+            r#"
+struct RawIdentTable { r#type: u32 }
+
+fn main() -> RawIdentTable {
+    RawIdentTable { t$0: 42 }
+}
+"#,
+            r#"
+struct RawIdentTable { r#type: u32 }
+
+fn main() -> RawIdentTable {
+    RawIdentTable { r#type: 42 }
+}
 "#,
         );
     }
@@ -1290,18 +1335,28 @@ fn foo(…) []
 
     #[test]
     fn struct_field_method_ref() {
-        check(
+        check_kinds(
             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,
@@ -1312,15 +1367,6 @@ 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",
-                    },
                 ]
             "#]],
         );
@@ -1348,10 +1394,10 @@ fn foo() {
                 lc foo [type+local]
                 ev Foo::A(…) [type_could_unify]
                 ev Foo::B [type_could_unify]
+                fn foo() []
                 en Foo []
                 fn baz() []
                 fn bar() []
-                fn foo() []
             "#]],
         );
     }
@@ -1359,7 +1405,6 @@ fn foo() []
     #[test]
     fn postfix_completion_relevance() {
         check_relevance_for_kinds(
-            &[CompletionKind::Postfix, CompletionKind::Magic],
             r#"
 mod ops {
     pub trait Not {
@@ -1376,7 +1421,8 @@ fn not(self) -> bool { if self { false } else { true }}
 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]
@@ -1386,9 +1432,6 @@ fn main() {
                 sn refm []
                 sn match []
                 sn box []
-                sn ok []
-                sn err []
-                sn some []
                 sn dbg []
                 sn dbgr []
                 sn call []