aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/completions')
-rw-r--r--crates/ide_completion/src/completions/attribute.rs38
-rw-r--r--crates/ide_completion/src/completions/dot.rs6
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs280
-rw-r--r--crates/ide_completion/src/completions/fn_param.rs26
-rw-r--r--crates/ide_completion/src/completions/keyword.rs85
-rw-r--r--crates/ide_completion/src/completions/mod_.rs6
-rw-r--r--crates/ide_completion/src/completions/postfix.rs21
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs18
-rw-r--r--crates/ide_completion/src/completions/record.rs15
-rw-r--r--crates/ide_completion/src/completions/snippet.rs25
-rw-r--r--crates/ide_completion/src/completions/trait_impl.rs32
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs12
12 files changed, 377 insertions, 187 deletions
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 3a5bc4381..e846678b4 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -39,20 +39,21 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
39} 39}
40 40
41fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) { 41fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) {
42 for attr_completion in ATTRIBUTES { 42 let is_inner = attribute.kind() == ast::AttrKind::Inner;
43 for attr_completion in ATTRIBUTES.iter().filter(|compl| is_inner || !compl.prefer_inner) {
43 let mut item = CompletionItem::new( 44 let mut item = CompletionItem::new(
44 CompletionKind::Attribute, 45 CompletionKind::Attribute,
45 ctx.source_range(), 46 ctx.source_range(),
46 attr_completion.label, 47 attr_completion.label,
47 ) 48 );
48 .kind(CompletionItemKind::Attribute); 49 item.kind(CompletionItemKind::Attribute);
49 50
50 if let Some(lookup) = attr_completion.lookup { 51 if let Some(lookup) = attr_completion.lookup {
51 item = item.lookup_by(lookup); 52 item.lookup_by(lookup);
52 } 53 }
53 54
54 if let Some((snippet, cap)) = attr_completion.snippet.zip(ctx.config.snippet_cap) { 55 if let Some((snippet, cap)) = attr_completion.snippet.zip(ctx.config.snippet_cap) {
55 item = item.insert_snippet(cap, snippet); 56 item.insert_snippet(cap, snippet);
56 } 57 }
57 58
58 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner { 59 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
@@ -167,16 +168,20 @@ fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input:
167 ); 168 );
168 let lookup = components.join(", "); 169 let lookup = components.join(", ");
169 let label = components.iter().rev().join(", "); 170 let label = components.iter().rev().join(", ");
170 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label) 171 let mut item =
171 .lookup_by(lookup) 172 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
172 .kind(CompletionItemKind::Attribute) 173 item.lookup_by(lookup).kind(CompletionItemKind::Attribute);
173 .add_to(acc) 174 item.add_to(acc);
174 } 175 }
175 176
176 for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) { 177 for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) {
177 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), custom_derive_name) 178 let mut item = CompletionItem::new(
178 .kind(CompletionItemKind::Attribute) 179 CompletionKind::Attribute,
179 .add_to(acc) 180 ctx.source_range(),
181 custom_derive_name,
182 );
183 item.kind(CompletionItemKind::Attribute);
184 item.add_to(acc);
180 } 185 }
181 } 186 }
182} 187}
@@ -192,14 +197,13 @@ fn complete_lint(
192 .into_iter() 197 .into_iter()
193 .filter(|completion| !existing_lints.contains(completion.label)) 198 .filter(|completion| !existing_lints.contains(completion.label))
194 { 199 {
195 CompletionItem::new( 200 let mut item = CompletionItem::new(
196 CompletionKind::Attribute, 201 CompletionKind::Attribute,
197 ctx.source_range(), 202 ctx.source_range(),
198 lint_completion.label, 203 lint_completion.label,
199 ) 204 );
200 .kind(CompletionItemKind::Attribute) 205 item.kind(CompletionItemKind::Attribute).detail(lint_completion.description);
201 .detail(lint_completion.description) 206 item.add_to(acc)
202 .add_to(acc)
203 } 207 }
204 } 208 }
205} 209}
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index 084d7721d..5ee9a9f07 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -2,7 +2,6 @@
2 2
3use hir::{HasVisibility, Type}; 3use hir::{HasVisibility, Type};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use test_utils::mark;
6 5
7use crate::{context::CompletionContext, Completions}; 6use crate::{context::CompletionContext, Completions};
8 7
@@ -19,7 +18,7 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
19 }; 18 };
20 19
21 if ctx.is_call { 20 if ctx.is_call {
22 mark::hit!(test_no_struct_field_completion_for_method_call); 21 cov_mark::hit!(test_no_struct_field_completion_for_method_call);
23 } else { 22 } else {
24 complete_fields(acc, ctx, &receiver_ty); 23 complete_fields(acc, ctx, &receiver_ty);
25 } 24 }
@@ -62,7 +61,6 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
62#[cfg(test)] 61#[cfg(test)]
63mod tests { 62mod tests {
64 use expect_test::{expect, Expect}; 63 use expect_test::{expect, Expect};
65 use test_utils::mark;
66 64
67 use crate::{test_utils::completion_list, CompletionKind}; 65 use crate::{test_utils::completion_list, CompletionKind};
68 66
@@ -122,7 +120,7 @@ impl A {
122 120
123 #[test] 121 #[test]
124 fn test_no_struct_field_completion_for_method_call() { 122 fn test_no_struct_field_completion_for_method_call() {
125 mark::check!(test_no_struct_field_completion_for_method_call); 123 cov_mark::check!(test_no_struct_field_completion_for_method_call);
126 check( 124 check(
127 r#" 125 r#"
128struct A { the_field: u32 } 126struct A { the_field: u32 }
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index da8375af9..391a11c91 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -21,6 +21,46 @@
21//! ``` 21//! ```
22//! 22//!
23//! Also completes associated items, that require trait imports. 23//! Also completes associated items, that require trait imports.
24//! If any unresolved and/or partially-qualified path predeces the input, it will be taken into account.
25//! Currently, only the imports with their import path ending with the whole qialifier will be proposed
26//! (no fuzzy matching for qualifier).
27//!
28//! ```
29//! mod foo {
30//! pub mod bar {
31//! pub struct Item;
32//!
33//! impl Item {
34//! pub const TEST_ASSOC: usize = 3;
35//! }
36//! }
37//! }
38//!
39//! fn main() {
40//! bar::Item::TEST_A$0
41//! }
42//! ```
43//! ->
44//! ```
45//! use foo::bar;
46//!
47//! mod foo {
48//! pub mod bar {
49//! pub struct Item;
50//!
51//! impl Item {
52//! pub const TEST_ASSOC: usize = 3;
53//! }
54//! }
55//! }
56//!
57//! fn main() {
58//! bar::Item::TEST_ASSOC
59//! }
60//! ```
61//!
62//! NOTE: currently, if an assoc item comes from a trait that's not currently imported and it also has an unresolved and/or partially-qualified path,
63//! no imports will be proposed.
24//! 64//!
25//! .Fuzzy search details 65//! .Fuzzy search details
26//! 66//!
@@ -48,14 +88,13 @@
48//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding 88//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
49//! capability enabled. 89//! capability enabled.
50 90
51use hir::{AsAssocItem, ModPath, ScopeDef}; 91use hir::ModPath;
52use ide_db::helpers::{ 92use ide_db::helpers::{
53 import_assets::{ImportAssets, ImportCandidate}, 93 import_assets::{ImportAssets, ImportCandidate},
54 insert_use::ImportScope, 94 insert_use::ImportScope,
55}; 95};
56use rustc_hash::FxHashSet; 96use itertools::Itertools;
57use syntax::{AstNode, SyntaxNode, T}; 97use syntax::{AstNode, SyntaxNode, T};
58use test_utils::mark;
59 98
60use crate::{ 99use crate::{
61 context::CompletionContext, 100 context::CompletionContext,
@@ -93,50 +132,26 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
93 &ctx.sema, 132 &ctx.sema,
94 )?; 133 )?;
95 134
96 let scope_definitions = scope_definitions(ctx); 135 acc.add_all(
97 let mut all_mod_paths = import_assets 136 import_assets
98 .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind) 137 .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
99 .into_iter() 138 .into_iter()
100 .map(|(mod_path, item_in_ns)| { 139 .sorted_by_key(|located_import| {
101 let scope_item = match item_in_ns { 140 compute_fuzzy_completion_order_key(
102 hir::ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()), 141 &located_import.import_path,
103 hir::ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()), 142 &user_input_lowercased,
104 hir::ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()), 143 )
105 }; 144 })
106 (mod_path, scope_item) 145 .filter_map(|import| {
107 }) 146 render_resolution_with_import(
108 .filter(|(_, proposed_def)| !scope_definitions.contains(proposed_def)) 147 RenderContext::new(ctx),
109 .collect::<Vec<_>>(); 148 ImportEdit { import, scope: import_scope.clone() },
110 all_mod_paths.sort_by_cached_key(|(mod_path, _)| { 149 )
111 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) 150 }),
112 }); 151 );
113
114 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| {
115 let import_for_trait_assoc_item = match definition {
116 ScopeDef::ModuleDef(module_def) => module_def
117 .as_assoc_item(ctx.db)
118 .and_then(|assoc| assoc.containing_trait(ctx.db))
119 .is_some(),
120 _ => false,
121 };
122 let import_edit = ImportEdit {
123 import_path,
124 import_scope: import_scope.clone(),
125 import_for_trait_assoc_item,
126 };
127 render_resolution_with_import(RenderContext::new(ctx), import_edit, &definition)
128 }));
129 Some(()) 152 Some(())
130} 153}
131 154
132fn scope_definitions(ctx: &CompletionContext) -> FxHashSet<ScopeDef> {
133 let mut scope_definitions = FxHashSet::default();
134 ctx.scope.process_all_names(&mut |_, scope_def| {
135 scope_definitions.insert(scope_def);
136 });
137 scope_definitions
138}
139
140pub(crate) fn position_for_import<'a>( 155pub(crate) fn position_for_import<'a>(
141 ctx: &'a CompletionContext, 156 ctx: &'a CompletionContext,
142 import_candidate: Option<&ImportCandidate>, 157 import_candidate: Option<&ImportCandidate>,
@@ -161,23 +176,30 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
161 current_module, 176 current_module,
162 ctx.sema.type_of_expr(dot_receiver)?, 177 ctx.sema.type_of_expr(dot_receiver)?,
163 fuzzy_name, 178 fuzzy_name,
179 dot_receiver.syntax().clone(),
164 ) 180 )
165 } else { 181 } else {
166 let fuzzy_name_length = fuzzy_name.len(); 182 let fuzzy_name_length = fuzzy_name.len();
183 let approximate_node = match current_module.definition_source(ctx.db).value {
184 hir::ModuleSource::SourceFile(s) => s.syntax().clone(),
185 hir::ModuleSource::Module(m) => m.syntax().clone(),
186 hir::ModuleSource::BlockExpr(b) => b.syntax().clone(),
187 };
167 let assets_for_path = ImportAssets::for_fuzzy_path( 188 let assets_for_path = ImportAssets::for_fuzzy_path(
168 current_module, 189 current_module,
169 ctx.path_qual.clone(), 190 ctx.path_qual.clone(),
170 fuzzy_name, 191 fuzzy_name,
171 &ctx.sema, 192 &ctx.sema,
172 ); 193 approximate_node,
194 )?;
173 195
174 if matches!(assets_for_path.as_ref()?.import_candidate(), ImportCandidate::Path(_)) 196 if matches!(assets_for_path.import_candidate(), ImportCandidate::Path(_))
175 && fuzzy_name_length < 2 197 && fuzzy_name_length < 2
176 { 198 {
177 mark::hit!(ignore_short_input_for_path); 199 cov_mark::hit!(ignore_short_input_for_path);
178 None 200 None
179 } else { 201 } else {
180 assets_for_path 202 Some(assets_for_path)
181 } 203 }
182 } 204 }
183} 205}
@@ -186,12 +208,12 @@ fn compute_fuzzy_completion_order_key(
186 proposed_mod_path: &ModPath, 208 proposed_mod_path: &ModPath,
187 user_input_lowercased: &str, 209 user_input_lowercased: &str,
188) -> usize { 210) -> usize {
189 mark::hit!(certain_fuzzy_order_test); 211 cov_mark::hit!(certain_fuzzy_order_test);
190 let proposed_import_name = match proposed_mod_path.segments().last() { 212 let import_name = match proposed_mod_path.segments().last() {
191 Some(name) => name.to_string().to_lowercase(), 213 Some(name) => name.to_string().to_lowercase(),
192 None => return usize::MAX, 214 None => return usize::MAX,
193 }; 215 };
194 match proposed_import_name.match_indices(user_input_lowercased).next() { 216 match import_name.match_indices(user_input_lowercased).next() {
195 Some((first_matching_index, _)) => first_matching_index, 217 Some((first_matching_index, _)) => first_matching_index,
196 None => usize::MAX, 218 None => usize::MAX,
197 } 219 }
@@ -200,7 +222,6 @@ fn compute_fuzzy_completion_order_key(
200#[cfg(test)] 222#[cfg(test)]
201mod tests { 223mod tests {
202 use expect_test::{expect, Expect}; 224 use expect_test::{expect, Expect};
203 use test_utils::mark;
204 225
205 use crate::{ 226 use crate::{
206 item::CompletionKind, 227 item::CompletionKind,
@@ -295,7 +316,7 @@ fn main() {
295 316
296 #[test] 317 #[test]
297 fn short_paths_are_ignored() { 318 fn short_paths_are_ignored() {
298 mark::check!(ignore_short_input_for_path); 319 cov_mark::check!(ignore_short_input_for_path);
299 320
300 check( 321 check(
301 r#" 322 r#"
@@ -319,7 +340,7 @@ fn main() {
319 340
320 #[test] 341 #[test]
321 fn fuzzy_completions_come_in_specific_order() { 342 fn fuzzy_completions_come_in_specific_order() {
322 mark::check!(certain_fuzzy_order_test); 343 cov_mark::check!(certain_fuzzy_order_test);
323 check( 344 check(
324 r#" 345 r#"
325//- /lib.rs crate:dep 346//- /lib.rs crate:dep
@@ -775,4 +796,155 @@ fn main() {
775}"#, 796}"#,
776 ); 797 );
777 } 798 }
799
800 #[test]
801 fn unresolved_qualifier() {
802 let fixture = r#"
803mod foo {
804 pub mod bar {
805 pub mod baz {
806 pub struct Item;
807 }
808 }
809}
810
811fn main() {
812 bar::baz::Ite$0
813}"#;
814
815 check(
816 fixture,
817 expect![[r#"
818 st foo::bar::baz::Item
819 "#]],
820 );
821
822 check_edit(
823 "Item",
824 fixture,
825 r#"
826 use foo::bar;
827
828 mod foo {
829 pub mod bar {
830 pub mod baz {
831 pub struct Item;
832 }
833 }
834 }
835
836 fn main() {
837 bar::baz::Item
838 }"#,
839 );
840 }
841
842 #[test]
843 fn unresolved_assoc_item_container() {
844 let fixture = r#"
845mod foo {
846 pub struct Item;
847
848 impl Item {
849 pub const TEST_ASSOC: usize = 3;
850 }
851}
852
853fn main() {
854 Item::TEST_A$0
855}"#;
856
857 check(
858 fixture,
859 expect![[r#"
860 ct TEST_ASSOC (foo::Item)
861 "#]],
862 );
863
864 check_edit(
865 "TEST_ASSOC",
866 fixture,
867 r#"
868use foo::Item;
869
870mod foo {
871 pub struct Item;
872
873 impl Item {
874 pub const TEST_ASSOC: usize = 3;
875 }
876}
877
878fn main() {
879 Item::TEST_ASSOC
880}"#,
881 );
882 }
883
884 #[test]
885 fn unresolved_assoc_item_container_with_path() {
886 let fixture = r#"
887mod foo {
888 pub mod bar {
889 pub struct Item;
890
891 impl Item {
892 pub const TEST_ASSOC: usize = 3;
893 }
894 }
895}
896
897fn main() {
898 bar::Item::TEST_A$0
899}"#;
900
901 check(
902 fixture,
903 expect![[r#"
904 ct TEST_ASSOC (foo::bar::Item)
905 "#]],
906 );
907
908 check_edit(
909 "TEST_ASSOC",
910 fixture,
911 r#"
912use foo::bar;
913
914mod foo {
915 pub mod bar {
916 pub struct Item;
917
918 impl Item {
919 pub const TEST_ASSOC: usize = 3;
920 }
921 }
922}
923
924fn main() {
925 bar::Item::TEST_ASSOC
926}"#,
927 );
928 }
929
930 #[test]
931 fn fuzzy_unresolved_path() {
932 check(
933 r#"
934mod foo {
935 pub mod bar {
936 pub struct Item;
937
938 impl Item {
939 pub const TEST_ASSOC: usize = 3;
940 }
941 }
942}
943
944fn main() {
945 bar::Ass$0
946}"#,
947 expect![[]],
948 )
949 }
778} 950}
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index 38e33a93e..0243dce56 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -25,9 +25,12 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
25 return; 25 return;
26 } 26 }
27 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { 27 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
28 let text = param.syntax().text().to_string(); 28 if let Some(pat) = param.pat() {
29 params.entry(text).or_insert(param); 29 let text = param.syntax().text().to_string();
30 }) 30 let lookup = pat.syntax().text().to_string();
31 params.entry(text).or_insert(lookup);
32 }
33 });
31 }; 34 };
32 35
33 for node in ctx.token.parent().ancestors() { 36 for node in ctx.token.parent().ancestors() {
@@ -50,18 +53,11 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
50 }; 53 };
51 } 54 }
52 55
53 params 56 params.into_iter().for_each(|(label, lookup)| {
54 .into_iter() 57 let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label);
55 .filter_map(|(label, param)| { 58 item.kind(CompletionItemKind::Binding).lookup_by(lookup);
56 let lookup = param.pat()?.syntax().text().to_string(); 59 item.add_to(acc)
57 Some((label, lookup)) 60 });
58 })
59 .for_each(|(label, lookup)| {
60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
61 .kind(CompletionItemKind::Binding)
62 .lookup_by(lookup)
63 .add_to(acc)
64 });
65} 61}
66 62
67#[cfg(test)] 63#[cfg(test)]
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index eb81f9765..b635e0ca3 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -1,7 +1,8 @@
1//! Completes keywords. 1//! Completes keywords.
2 2
3use std::iter;
4
3use syntax::SyntaxKind; 5use syntax::SyntaxKind;
4use test_utils::mark;
5 6
6use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; 7use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
7 8
@@ -11,29 +12,30 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
11 12
12 if ctx.use_item_syntax.is_some() { 13 if ctx.use_item_syntax.is_some() {
13 if ctx.path_qual.is_none() { 14 if ctx.path_qual.is_none() {
14 CompletionItem::new(CompletionKind::Keyword, source_range, "crate::") 15 let mut item = CompletionItem::new(CompletionKind::Keyword, source_range, "crate::");
15 .kind(CompletionItemKind::Keyword) 16 item.kind(CompletionItemKind::Keyword).insert_text("crate::");
16 .insert_text("crate::") 17 item.add_to(acc);
17 .add_to(acc); 18 }
19 let mut item = CompletionItem::new(CompletionKind::Keyword, source_range, "self");
20 item.kind(CompletionItemKind::Keyword);
21 item.add_to(acc);
22 if iter::successors(ctx.path_qual.clone(), |p| p.qualifier())
23 .all(|p| p.segment().and_then(|s| s.super_token()).is_some())
24 {
25 let mut item = CompletionItem::new(CompletionKind::Keyword, source_range, "super::");
26 item.kind(CompletionItemKind::Keyword).insert_text("super::");
27 item.add_to(acc);
18 } 28 }
19 CompletionItem::new(CompletionKind::Keyword, source_range, "self")
20 .kind(CompletionItemKind::Keyword)
21 .add_to(acc);
22 CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
23 .kind(CompletionItemKind::Keyword)
24 .insert_text("super::")
25 .add_to(acc);
26 } 29 }
27 30
28 // Suggest .await syntax for types that implement Future trait 31 // Suggest .await syntax for types that implement Future trait
29 if let Some(receiver) = &ctx.dot_receiver { 32 if let Some(receiver) = &ctx.dot_receiver {
30 if let Some(ty) = ctx.sema.type_of_expr(receiver) { 33 if let Some(ty) = ctx.sema.type_of_expr(receiver) {
31 if ty.impls_future(ctx.db) { 34 if ty.impls_future(ctx.db) {
32 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") 35 let mut item =
33 .kind(CompletionItemKind::Keyword) 36 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await");
34 .detail("expr.await") 37 item.kind(CompletionItemKind::Keyword).detail("expr.await").insert_text("await");
35 .insert_text("await") 38 item.add_to(acc);
36 .add_to(acc);
37 } 39 }
38 }; 40 };
39 } 41 }
@@ -41,11 +43,11 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
41 43
42pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 44pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
43 if ctx.token.kind() == SyntaxKind::COMMENT { 45 if ctx.token.kind() == SyntaxKind::COMMENT {
44 mark::hit!(no_keyword_completion_in_comments); 46 cov_mark::hit!(no_keyword_completion_in_comments);
45 return; 47 return;
46 } 48 }
47 if ctx.record_lit_syntax.is_some() { 49 if ctx.record_lit_syntax.is_some() {
48 mark::hit!(no_keyword_completion_in_record_lit); 50 cov_mark::hit!(no_keyword_completion_in_record_lit);
49 return; 51 return;
50 } 52 }
51 53
@@ -85,6 +87,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
85 if ctx.is_expr { 87 if ctx.is_expr {
86 add_keyword(ctx, acc, "match", "match $0 {}"); 88 add_keyword(ctx, acc, "match", "match $0 {}");
87 add_keyword(ctx, acc, "while", "while $0 {}"); 89 add_keyword(ctx, acc, "while", "while $0 {}");
90 add_keyword(ctx, acc, "while let", "while let $1 = $0 {}");
88 add_keyword(ctx, acc, "loop", "loop {$0}"); 91 add_keyword(ctx, acc, "loop", "loop {$0}");
89 add_keyword(ctx, acc, "if", "if $0 {}"); 92 add_keyword(ctx, acc, "if", "if $0 {}");
90 add_keyword(ctx, acc, "if let", "if let $1 = $0 {}"); 93 add_keyword(ctx, acc, "if let", "if let $1 = $0 {}");
@@ -159,29 +162,31 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
159} 162}
160 163
161fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) { 164fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
162 let builder = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw) 165 let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw);
163 .kind(CompletionItemKind::Keyword); 166 item.kind(CompletionItemKind::Keyword);
164 let builder = match ctx.config.snippet_cap { 167
168 match ctx.config.snippet_cap {
165 Some(cap) => { 169 Some(cap) => {
166 let tmp; 170 let tmp;
167 let snippet = if snippet.ends_with('}') && ctx.incomplete_let { 171 let snippet = if snippet.ends_with('}') && ctx.incomplete_let {
168 mark::hit!(let_semi); 172 cov_mark::hit!(let_semi);
169 tmp = format!("{};", snippet); 173 tmp = format!("{};", snippet);
170 &tmp 174 &tmp
171 } else { 175 } else {
172 snippet 176 snippet
173 }; 177 };
174 builder.insert_snippet(cap, snippet) 178 item.insert_snippet(cap, snippet);
179 }
180 None => {
181 item.insert_text(if snippet.contains('$') { kw } else { snippet });
175 } 182 }
176 None => builder.insert_text(if snippet.contains('$') { kw } else { snippet }),
177 }; 183 };
178 acc.add(builder.build()); 184 item.add_to(acc);
179} 185}
180 186
181#[cfg(test)] 187#[cfg(test)]
182mod tests { 188mod tests {
183 use expect_test::{expect, Expect}; 189 use expect_test::{expect, Expect};
184 use test_utils::mark;
185 190
186 use crate::{ 191 use crate::{
187 test_utils::{check_edit, completion_list}, 192 test_utils::{check_edit, completion_list},
@@ -204,9 +209,17 @@ mod tests {
204 "#]], 209 "#]],
205 ); 210 );
206 211
212 // FIXME: `self` shouldn't be shown here and the check below
207 check( 213 check(
208 r"use a::$0", 214 r"use a::$0",
209 expect![[r#" 215 expect![[r#"
216 kw self
217 "#]],
218 );
219
220 check(
221 r"use super::$0",
222 expect![[r#"
210 kw self 223 kw self
211 kw super:: 224 kw super::
212 "#]], 225 "#]],
@@ -215,9 +228,8 @@ mod tests {
215 check( 228 check(
216 r"use a::{b, $0}", 229 r"use a::{b, $0}",
217 expect![[r#" 230 expect![[r#"
218 kw self 231 kw self
219 kw super:: 232 "#]],
220 "#]],
221 ); 233 );
222 } 234 }
223 235
@@ -256,6 +268,7 @@ mod tests {
256 kw trait 268 kw trait
257 kw match 269 kw match
258 kw while 270 kw while
271 kw while let
259 kw loop 272 kw loop
260 kw if 273 kw if
261 kw if let 274 kw if let
@@ -283,6 +296,7 @@ mod tests {
283 kw trait 296 kw trait
284 kw match 297 kw match
285 kw while 298 kw while
299 kw while let
286 kw loop 300 kw loop
287 kw if 301 kw if
288 kw if let 302 kw if let
@@ -310,6 +324,7 @@ mod tests {
310 kw trait 324 kw trait
311 kw match 325 kw match
312 kw while 326 kw while
327 kw while let
313 kw loop 328 kw loop
314 kw if 329 kw if
315 kw if let 330 kw if let
@@ -344,6 +359,7 @@ fn quux() -> i32 {
344 expect![[r#" 359 expect![[r#"
345 kw match 360 kw match
346 kw while 361 kw while
362 kw while let
347 kw loop 363 kw loop
348 kw if 364 kw if
349 kw if let 365 kw if let
@@ -393,6 +409,7 @@ fn quux() -> i32 {
393 kw trait 409 kw trait
394 kw match 410 kw match
395 kw while 411 kw while
412 kw while let
396 kw loop 413 kw loop
397 kw if 414 kw if
398 kw if let 415 kw if let
@@ -475,7 +492,7 @@ fn quux() -> i32 {
475 492
476 #[test] 493 #[test]
477 fn no_keyword_completion_in_comments() { 494 fn no_keyword_completion_in_comments() {
478 mark::check!(no_keyword_completion_in_comments); 495 cov_mark::check!(no_keyword_completion_in_comments);
479 check( 496 check(
480 r#" 497 r#"
481fn test() { 498fn test() {
@@ -552,6 +569,7 @@ pub mod future {
552 expect![[r#" 569 expect![[r#"
553 kw match 570 kw match
554 kw while 571 kw while
572 kw while let
555 kw loop 573 kw loop
556 kw if 574 kw if
557 kw if let 575 kw if let
@@ -579,7 +597,7 @@ struct Foo {
579 597
580 #[test] 598 #[test]
581 fn skip_struct_initializer() { 599 fn skip_struct_initializer() {
582 mark::check!(no_keyword_completion_in_record_lit); 600 cov_mark::check!(no_keyword_completion_in_record_lit);
583 check( 601 check(
584 r#" 602 r#"
585struct Foo { 603struct Foo {
@@ -611,6 +629,7 @@ fn foo() {
611 expect![[r#" 629 expect![[r#"
612 kw match 630 kw match
613 kw while 631 kw while
632 kw while let
614 kw loop 633 kw loop
615 kw if 634 kw if
616 kw if let 635 kw if let
@@ -622,7 +641,7 @@ fn foo() {
622 641
623 #[test] 642 #[test]
624 fn let_semi() { 643 fn let_semi() {
625 mark::check!(let_semi); 644 cov_mark::check!(let_semi);
626 check_edit( 645 check_edit(
627 "match", 646 "match",
628 r#" 647 r#"
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs
index 352fc7c77..4f9415736 100644
--- a/crates/ide_completion/src/completions/mod_.rs
+++ b/crates/ide_completion/src/completions/mod_.rs
@@ -80,9 +80,9 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
80 if mod_under_caret.semicolon_token().is_none() { 80 if mod_under_caret.semicolon_token().is_none() {
81 label.push(';'); 81 label.push(';');
82 } 82 }
83 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label) 83 let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label);
84 .kind(SymbolKind::Module) 84 item.kind(SymbolKind::Module);
85 .add_to(acc) 85 item.add_to(acc)
86 }); 86 });
87 87
88 Some(()) 88 Some(())
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 9c34ed0b6..ac69b720a 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -187,6 +187,16 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
187 ctx, 187 ctx,
188 cap, 188 cap,
189 &dot_receiver, 189 &dot_receiver,
190 "err",
191 "Err(expr)",
192 &format!("Err({})", receiver_text),
193 )
194 .add_to(acc);
195
196 postfix_snippet(
197 ctx,
198 cap,
199 &dot_receiver,
190 "some", 200 "some",
191 "Some(expr)", 201 "Some(expr)",
192 &format!("Some({})", receiver_text), 202 &format!("Some({})", receiver_text),
@@ -287,10 +297,9 @@ fn postfix_snippet(
287 let delete_range = TextRange::new(receiver_range.start(), ctx.source_range().end()); 297 let delete_range = TextRange::new(receiver_range.start(), ctx.source_range().end());
288 TextEdit::replace(delete_range, snippet.to_string()) 298 TextEdit::replace(delete_range, snippet.to_string())
289 }; 299 };
290 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) 300 let mut item = CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label);
291 .detail(detail) 301 item.detail(detail).kind(CompletionItemKind::Snippet).snippet_edit(cap, edit);
292 .kind(CompletionItemKind::Snippet) 302 item
293 .snippet_edit(cap, edit)
294} 303}
295 304
296#[cfg(test)] 305#[cfg(test)]
@@ -325,6 +334,7 @@ fn main() {
325 sn match match expr {} 334 sn match match expr {}
326 sn box Box::new(expr) 335 sn box Box::new(expr)
327 sn ok Ok(expr) 336 sn ok Ok(expr)
337 sn err Err(expr)
328 sn some Some(expr) 338 sn some Some(expr)
329 sn dbg dbg!(expr) 339 sn dbg dbg!(expr)
330 sn dbgr dbg!(&expr) 340 sn dbgr dbg!(&expr)
@@ -357,6 +367,7 @@ fn main() {
357 sn match match expr {} 367 sn match match expr {}
358 sn box Box::new(expr) 368 sn box Box::new(expr)
359 sn ok Ok(expr) 369 sn ok Ok(expr)
370 sn err Err(expr)
360 sn some Some(expr) 371 sn some Some(expr)
361 sn dbg dbg!(expr) 372 sn dbg dbg!(expr)
362 sn dbgr dbg!(&expr) 373 sn dbgr dbg!(&expr)
@@ -380,6 +391,7 @@ fn main() {
380 sn match match expr {} 391 sn match match expr {}
381 sn box Box::new(expr) 392 sn box Box::new(expr)
382 sn ok Ok(expr) 393 sn ok Ok(expr)
394 sn err Err(expr)
383 sn some Some(expr) 395 sn some Some(expr)
384 sn dbg dbg!(expr) 396 sn dbg dbg!(expr)
385 sn dbgr dbg!(&expr) 397 sn dbgr dbg!(&expr)
@@ -408,6 +420,7 @@ fn main() {
408 sn match match expr {} 420 sn match match expr {}
409 sn box Box::new(expr) 421 sn box Box::new(expr)
410 sn ok Ok(expr) 422 sn ok Ok(expr)
423 sn err Err(expr)
411 sn some Some(expr) 424 sn some Some(expr)
412 sn dbg dbg!(expr) 425 sn dbg dbg!(expr)
413 sn dbgr dbg!(&expr) 426 sn dbgr dbg!(&expr)
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 2afa6979e..df74b739e 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -3,7 +3,6 @@
3use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; 3use hir::{Adt, HasVisibility, PathResolution, ScopeDef};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use syntax::AstNode; 5use syntax::AstNode;
6use test_utils::mark;
7 6
8use crate::{CompletionContext, Completions}; 7use crate::{CompletionContext, Completions};
9 8
@@ -39,7 +38,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
39 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { 38 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
40 if name_ref.syntax().text() == name.to_string().as_str() { 39 if name_ref.syntax().text() == name.to_string().as_str() {
41 // for `use self::foo$0`, don't suggest `foo` as a completion 40 // for `use self::foo$0`, don't suggest `foo` as a completion
42 mark::hit!(dont_complete_current_use); 41 cov_mark::hit!(dont_complete_current_use);
43 continue; 42 continue;
44 } 43 }
45 } 44 }
@@ -81,9 +80,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
81 return None; 80 return None;
82 } 81 }
83 match item { 82 match item {
84 hir::AssocItem::Function(func) => { 83 hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
85 acc.add_function(ctx, func, None);
86 }
87 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), 84 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
88 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), 85 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
89 } 86 }
@@ -110,9 +107,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
110 continue; 107 continue;
111 } 108 }
112 match item { 109 match item {
113 hir::AssocItem::Function(func) => { 110 hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
114 acc.add_function(ctx, func, None);
115 }
116 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), 111 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
117 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), 112 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
118 } 113 }
@@ -143,9 +138,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
143 // them. 138 // them.
144 if seen.insert(item) { 139 if seen.insert(item) {
145 match item { 140 match item {
146 hir::AssocItem::Function(func) => { 141 hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
147 acc.add_function(ctx, func, None);
148 }
149 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), 142 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
150 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), 143 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
151 } 144 }
@@ -161,7 +154,6 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
161#[cfg(test)] 154#[cfg(test)]
162mod tests { 155mod tests {
163 use expect_test::{expect, Expect}; 156 use expect_test::{expect, Expect};
164 use test_utils::mark;
165 157
166 use crate::{ 158 use crate::{
167 test_utils::{check_edit, completion_list}, 159 test_utils::{check_edit, completion_list},
@@ -180,7 +172,7 @@ mod tests {
180 172
181 #[test] 173 #[test]
182 fn dont_complete_current_use() { 174 fn dont_complete_current_use() {
183 mark::check!(dont_complete_current_use); 175 cov_mark::check!(dont_complete_current_use);
184 check(r#"use self::foo$0;"#, expect![[""]]); 176 check(r#"use self::foo$0;"#, expect![[""]]);
185 } 177 }
186 178
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs
index 0a7927eb8..2f95b8687 100644
--- a/crates/ide_completion/src/completions/record.rs
+++ b/crates/ide_completion/src/completions/record.rs
@@ -22,16 +22,13 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
22 let completion_text = completion_text 22 let completion_text = completion_text
23 .strip_prefix(ctx.token.to_string().as_str()) 23 .strip_prefix(ctx.token.to_string().as_str())
24 .unwrap_or(completion_text); 24 .unwrap_or(completion_text);
25 acc.add( 25 let mut item = CompletionItem::new(
26 CompletionItem::new( 26 CompletionKind::Snippet,
27 CompletionKind::Snippet, 27 ctx.source_range(),
28 ctx.source_range(), 28 "..Default::default()",
29 "..Default::default()",
30 )
31 .insert_text(completion_text)
32 .kind(SymbolKind::Field)
33 .build(),
34 ); 29 );
30 item.insert_text(completion_text).kind(SymbolKind::Field);
31 item.add_to(acc);
35 } 32 }
36 33
37 missing_fields 34 missing_fields
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index df17a15c5..7f7830976 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -8,9 +8,9 @@ use crate::{
8}; 8};
9 9
10fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { 10fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
11 CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), label) 11 let mut item = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), label);
12 .insert_snippet(cap, snippet) 12 item.insert_snippet(cap, snippet).kind(CompletionItemKind::Snippet);
13 .kind(CompletionItemKind::Snippet) 13 item
14} 14}
15 15
16pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { 16pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) {
@@ -35,7 +35,7 @@ pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionConte
35 None => return, 35 None => return,
36 }; 36 };
37 37
38 snippet( 38 let mut item = snippet(
39 ctx, 39 ctx,
40 cap, 40 cap,
41 "tmod (Test module)", 41 "tmod (Test module)",
@@ -49,11 +49,11 @@ mod tests {
49 $0 49 $0
50 } 50 }
51}", 51}",
52 ) 52 );
53 .lookup_by("tmod") 53 item.lookup_by("tmod");
54 .add_to(acc); 54 item.add_to(acc);
55 55
56 snippet( 56 let mut item = snippet(
57 ctx, 57 ctx,
58 cap, 58 cap,
59 "tfn (Test function)", 59 "tfn (Test function)",
@@ -62,11 +62,12 @@ mod tests {
62fn ${1:feature}() { 62fn ${1:feature}() {
63 $0 63 $0
64}", 64}",
65 ) 65 );
66 .lookup_by("tfn") 66 item.lookup_by("tfn");
67 .add_to(acc); 67 item.add_to(acc);
68 68
69 snippet(ctx, cap, "macro_rules", "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}").add_to(acc); 69 let item = snippet(ctx, cap, "macro_rules", "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}");
70 item.add_to(acc);
70} 71}
71 72
72#[cfg(test)] 73#[cfg(test)]
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs
index b999540b8..5a7361f8e 100644
--- a/crates/ide_completion/src/completions/trait_impl.rs
+++ b/crates/ide_completion/src/completions/trait_impl.rs
@@ -145,9 +145,8 @@ fn add_function_impl(
145 format!("fn {}(..)", fn_name) 145 format!("fn {}(..)", fn_name)
146 }; 146 };
147 147
148 let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) 148 let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label);
149 .lookup_by(fn_name) 149 item.lookup_by(fn_name).set_documentation(func.docs(ctx.db));
150 .set_documentation(func.docs(ctx.db));
151 150
152 let completion_kind = if func.self_param(ctx.db).is_some() { 151 let completion_kind = if func.self_param(ctx.db).is_some() {
153 CompletionItemKind::Method 152 CompletionItemKind::Method
@@ -161,15 +160,15 @@ fn add_function_impl(
161 match ctx.config.snippet_cap { 160 match ctx.config.snippet_cap {
162 Some(cap) => { 161 Some(cap) => {
163 let snippet = format!("{} {{\n $0\n}}", function_decl); 162 let snippet = format!("{} {{\n $0\n}}", function_decl);
164 builder.snippet_edit(cap, TextEdit::replace(range, snippet)) 163 item.snippet_edit(cap, TextEdit::replace(range, snippet));
165 } 164 }
166 None => { 165 None => {
167 let header = format!("{} {{", function_decl); 166 let header = format!("{} {{", function_decl);
168 builder.text_edit(TextEdit::replace(range, header)) 167 item.text_edit(TextEdit::replace(range, header));
169 } 168 }
170 } 169 };
171 .kind(completion_kind) 170 item.kind(completion_kind);
172 .add_to(acc); 171 item.add_to(acc);
173 } 172 }
174} 173}
175 174
@@ -185,12 +184,12 @@ fn add_type_alias_impl(
185 184
186 let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end()); 185 let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end());
187 186
188 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 187 let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
189 .text_edit(TextEdit::replace(range, snippet)) 188 item.text_edit(TextEdit::replace(range, snippet))
190 .lookup_by(alias_name) 189 .lookup_by(alias_name)
191 .kind(SymbolKind::TypeAlias) 190 .kind(SymbolKind::TypeAlias)
192 .set_documentation(type_alias.docs(ctx.db)) 191 .set_documentation(type_alias.docs(ctx.db));
193 .add_to(acc); 192 item.add_to(acc);
194} 193}
195 194
196fn add_const_impl( 195fn add_const_impl(
@@ -208,12 +207,13 @@ fn add_const_impl(
208 let range = 207 let range =
209 TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); 208 TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
210 209
211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 210 let mut item =
212 .text_edit(TextEdit::replace(range, snippet)) 211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
212 item.text_edit(TextEdit::replace(range, snippet))
213 .lookup_by(const_name) 213 .lookup_by(const_name)
214 .kind(SymbolKind::Const) 214 .kind(SymbolKind::Const)
215 .set_documentation(const_.docs(ctx.db)) 215 .set_documentation(const_.docs(ctx.db));
216 .add_to(acc); 216 item.add_to(acc);
217 } 217 }
218 } 218 }
219} 219}
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index e9d0ff665..044dfd160 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -2,7 +2,6 @@
2 2
3use hir::ScopeDef; 3use hir::ScopeDef;
4use syntax::AstNode; 4use syntax::AstNode;
5use test_utils::mark;
6 5
7use crate::{CompletionContext, Completions}; 6use crate::{CompletionContext, Completions};
8 7
@@ -30,13 +29,13 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
30 29
31 ctx.scope.process_all_names(&mut |name, res| { 30 ctx.scope.process_all_names(&mut |name, res| {
32 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { 31 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
33 mark::hit!(skip_lifetime_completion); 32 cov_mark::hit!(skip_lifetime_completion);
34 return; 33 return;
35 } 34 }
36 if ctx.use_item_syntax.is_some() { 35 if ctx.use_item_syntax.is_some() {
37 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { 36 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
38 if name_ref.syntax().text() == name.to_string().as_str() { 37 if name_ref.syntax().text() == name.to_string().as_str() {
39 mark::hit!(self_fulfilling_completion); 38 cov_mark::hit!(self_fulfilling_completion);
40 return; 39 return;
41 } 40 }
42 } 41 }
@@ -48,7 +47,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
48#[cfg(test)] 47#[cfg(test)]
49mod tests { 48mod tests {
50 use expect_test::{expect, Expect}; 49 use expect_test::{expect, Expect};
51 use test_utils::mark;
52 50
53 use crate::{ 51 use crate::{
54 test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, 52 test_utils::{check_edit, completion_list_with_config, TEST_CONFIG},
@@ -66,7 +64,7 @@ mod tests {
66 64
67 #[test] 65 #[test]
68 fn self_fulfilling_completion() { 66 fn self_fulfilling_completion() {
69 mark::check!(self_fulfilling_completion); 67 cov_mark::check!(self_fulfilling_completion);
70 check( 68 check(
71 r#" 69 r#"
72use foo$0 70use foo$0
@@ -185,7 +183,7 @@ fn quux() {
185 183
186 #[test] 184 #[test]
187 fn completes_if_prefix_is_keyword() { 185 fn completes_if_prefix_is_keyword() {
188 mark::check!(completes_if_prefix_is_keyword); 186 cov_mark::check!(completes_if_prefix_is_keyword);
189 check_edit( 187 check_edit(
190 "wherewolf", 188 "wherewolf",
191 r#" 189 r#"
@@ -223,7 +221,7 @@ fn main() {
223 221
224 #[test] 222 #[test]
225 fn does_not_complete_lifetimes() { 223 fn does_not_complete_lifetimes() {
226 mark::check!(skip_lifetime_completion); 224 cov_mark::check!(skip_lifetime_completion);
227 check( 225 check(
228 r#"fn quux<'a>() { $0 }"#, 226 r#"fn quux<'a>() { $0 }"#,
229 expect![[r#" 227 expect![[r#"