aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion')
-rw-r--r--crates/ide_completion/Cargo.toml1
-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/keyword.rs14
-rw-r--r--crates/ide_completion/src/completions/postfix.rs14
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs6
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs12
-rw-r--r--crates/ide_completion/src/context.rs4
-rw-r--r--crates/ide_completion/src/item.rs58
-rw-r--r--crates/ide_completion/src/lib.rs28
-rw-r--r--crates/ide_completion/src/render.rs45
-rw-r--r--crates/ide_completion/src/render/builder_ext.rs9
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs7
-rw-r--r--crates/ide_completion/src/render/function.rs11
-rw-r--r--crates/ide_completion/src/render/macro_.rs7
15 files changed, 335 insertions, 167 deletions
diff --git a/crates/ide_completion/Cargo.toml b/crates/ide_completion/Cargo.toml
index c09101ccb..84aa40736 100644
--- a/crates/ide_completion/Cargo.toml
+++ b/crates/ide_completion/Cargo.toml
@@ -10,6 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1"
13itertools = "0.10.0" 14itertools = "0.10.0"
14log = "0.4.8" 15log = "0.4.8"
15rustc-hash = "1.1.0" 16rustc-hash = "1.1.0"
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/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 03c6dd454..80aa9fb06 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -3,7 +3,6 @@
3use std::iter; 3use std::iter;
4 4
5use syntax::SyntaxKind; 5use syntax::SyntaxKind;
6use test_utils::mark;
7 6
8use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; 7use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
9 8
@@ -47,11 +46,11 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
47 46
48pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 47pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
49 if ctx.token.kind() == SyntaxKind::COMMENT { 48 if ctx.token.kind() == SyntaxKind::COMMENT {
50 mark::hit!(no_keyword_completion_in_comments); 49 cov_mark::hit!(no_keyword_completion_in_comments);
51 return; 50 return;
52 } 51 }
53 if ctx.record_lit_syntax.is_some() { 52 if ctx.record_lit_syntax.is_some() {
54 mark::hit!(no_keyword_completion_in_record_lit); 53 cov_mark::hit!(no_keyword_completion_in_record_lit);
55 return; 54 return;
56 } 55 }
57 56
@@ -172,7 +171,7 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet
172 Some(cap) => { 171 Some(cap) => {
173 let tmp; 172 let tmp;
174 let snippet = if snippet.ends_with('}') && ctx.incomplete_let { 173 let snippet = if snippet.ends_with('}') && ctx.incomplete_let {
175 mark::hit!(let_semi); 174 cov_mark::hit!(let_semi);
176 tmp = format!("{};", snippet); 175 tmp = format!("{};", snippet);
177 &tmp 176 &tmp
178 } else { 177 } else {
@@ -188,7 +187,6 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet
188#[cfg(test)] 187#[cfg(test)]
189mod tests { 188mod tests {
190 use expect_test::{expect, Expect}; 189 use expect_test::{expect, Expect};
191 use test_utils::mark;
192 190
193 use crate::{ 191 use crate::{
194 test_utils::{check_edit, completion_list}, 192 test_utils::{check_edit, completion_list},
@@ -494,7 +492,7 @@ fn quux() -> i32 {
494 492
495 #[test] 493 #[test]
496 fn no_keyword_completion_in_comments() { 494 fn no_keyword_completion_in_comments() {
497 mark::check!(no_keyword_completion_in_comments); 495 cov_mark::check!(no_keyword_completion_in_comments);
498 check( 496 check(
499 r#" 497 r#"
500fn test() { 498fn test() {
@@ -599,7 +597,7 @@ struct Foo {
599 597
600 #[test] 598 #[test]
601 fn skip_struct_initializer() { 599 fn skip_struct_initializer() {
602 mark::check!(no_keyword_completion_in_record_lit); 600 cov_mark::check!(no_keyword_completion_in_record_lit);
603 check( 601 check(
604 r#" 602 r#"
605struct Foo { 603struct Foo {
@@ -643,7 +641,7 @@ fn foo() {
643 641
644 #[test] 642 #[test]
645 fn let_semi() { 643 fn let_semi() {
646 mark::check!(let_semi); 644 cov_mark::check!(let_semi);
647 check_edit( 645 check_edit(
648 "match", 646 "match",
649 r#" 647 r#"
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 9c34ed0b6..d45ad7944 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),
@@ -325,6 +335,7 @@ fn main() {
325 sn match match expr {} 335 sn match match expr {}
326 sn box Box::new(expr) 336 sn box Box::new(expr)
327 sn ok Ok(expr) 337 sn ok Ok(expr)
338 sn err Err(expr)
328 sn some Some(expr) 339 sn some Some(expr)
329 sn dbg dbg!(expr) 340 sn dbg dbg!(expr)
330 sn dbgr dbg!(&expr) 341 sn dbgr dbg!(&expr)
@@ -357,6 +368,7 @@ fn main() {
357 sn match match expr {} 368 sn match match expr {}
358 sn box Box::new(expr) 369 sn box Box::new(expr)
359 sn ok Ok(expr) 370 sn ok Ok(expr)
371 sn err Err(expr)
360 sn some Some(expr) 372 sn some Some(expr)
361 sn dbg dbg!(expr) 373 sn dbg dbg!(expr)
362 sn dbgr dbg!(&expr) 374 sn dbgr dbg!(&expr)
@@ -380,6 +392,7 @@ fn main() {
380 sn match match expr {} 392 sn match match expr {}
381 sn box Box::new(expr) 393 sn box Box::new(expr)
382 sn ok Ok(expr) 394 sn ok Ok(expr)
395 sn err Err(expr)
383 sn some Some(expr) 396 sn some Some(expr)
384 sn dbg dbg!(expr) 397 sn dbg dbg!(expr)
385 sn dbgr dbg!(&expr) 398 sn dbgr dbg!(&expr)
@@ -408,6 +421,7 @@ fn main() {
408 sn match match expr {} 421 sn match match expr {}
409 sn box Box::new(expr) 422 sn box Box::new(expr)
410 sn ok Ok(expr) 423 sn ok Ok(expr)
424 sn err Err(expr)
411 sn some Some(expr) 425 sn some Some(expr)
412 sn dbg dbg!(expr) 426 sn dbg dbg!(expr)
413 sn dbgr dbg!(&expr) 427 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 72fb757b1..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 }
@@ -155,7 +154,6 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
155#[cfg(test)] 154#[cfg(test)]
156mod tests { 155mod tests {
157 use expect_test::{expect, Expect}; 156 use expect_test::{expect, Expect};
158 use test_utils::mark;
159 157
160 use crate::{ 158 use crate::{
161 test_utils::{check_edit, completion_list}, 159 test_utils::{check_edit, completion_list},
@@ -174,7 +172,7 @@ mod tests {
174 172
175 #[test] 173 #[test]
176 fn dont_complete_current_use() { 174 fn dont_complete_current_use() {
177 mark::check!(dont_complete_current_use); 175 cov_mark::check!(dont_complete_current_use);
178 check(r#"use self::foo$0;"#, expect![[""]]); 176 check(r#"use self::foo$0;"#, expect![[""]]);
179 } 177 }
180 178
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#"
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 3db357855..17d9a3adf 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -7,7 +7,7 @@ use syntax::{
7 algo::find_node_at_offset, ast, match_ast, AstNode, NodeOrToken, SyntaxKind::*, SyntaxNode, 7 algo::find_node_at_offset, ast, match_ast, AstNode, NodeOrToken, SyntaxKind::*, SyntaxNode,
8 SyntaxToken, TextRange, TextSize, 8 SyntaxToken, TextRange, TextSize,
9}; 9};
10use test_utils::mark; 10
11use text_edit::Indel; 11use text_edit::Indel;
12 12
13use crate::{ 13use crate::{
@@ -240,7 +240,7 @@ impl<'a> CompletionContext<'a> {
240 // check kind of macro-expanded token, but use range of original token 240 // check kind of macro-expanded token, but use range of original token
241 let kind = self.token.kind(); 241 let kind = self.token.kind();
242 if kind == IDENT || kind == UNDERSCORE || kind.is_keyword() { 242 if kind == IDENT || kind == UNDERSCORE || kind.is_keyword() {
243 mark::hit!(completes_if_prefix_is_keyword); 243 cov_mark::hit!(completes_if_prefix_is_keyword);
244 self.original_token.text_range() 244 self.original_token.text_range()
245 } else { 245 } else {
246 TextRange::empty(self.position.offset) 246 TextRange::empty(self.position.offset)
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 9b2435c4b..b16f0775a 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -2,15 +2,16 @@
2 2
3use std::fmt; 3use std::fmt;
4 4
5use hir::{Documentation, ModPath, Mutability}; 5use hir::{Documentation, Mutability};
6use ide_db::{ 6use ide_db::{
7 helpers::{ 7 helpers::{
8 import_assets::LocatedImport,
8 insert_use::{self, ImportScope, InsertUseConfig}, 9 insert_use::{self, ImportScope, InsertUseConfig},
9 mod_path_to_ast, SnippetCap, 10 mod_path_to_ast, SnippetCap,
10 }, 11 },
11 SymbolKind, 12 SymbolKind,
12}; 13};
13use stdx::{impl_from, never}; 14use stdx::{format_to, impl_from, never};
14use syntax::{algo, TextRange}; 15use syntax::{algo, TextRange};
15use text_edit::TextEdit; 16use text_edit::TextEdit;
16 17
@@ -207,7 +208,7 @@ impl CompletionItem {
207 lookup: None, 208 lookup: None,
208 kind: None, 209 kind: None,
209 text_edit: None, 210 text_edit: None,
210 deprecated: None, 211 deprecated: false,
211 trigger_call_info: None, 212 trigger_call_info: None,
212 score: None, 213 score: None,
213 ref_match: None, 214 ref_match: None,
@@ -272,9 +273,8 @@ impl CompletionItem {
272/// An extra import to add after the completion is applied. 273/// An extra import to add after the completion is applied.
273#[derive(Debug, Clone)] 274#[derive(Debug, Clone)]
274pub struct ImportEdit { 275pub struct ImportEdit {
275 pub import_path: ModPath, 276 pub import: LocatedImport,
276 pub import_scope: ImportScope, 277 pub scope: ImportScope,
277 pub import_for_trait_assoc_item: bool,
278} 278}
279 279
280impl ImportEdit { 280impl ImportEdit {
@@ -284,7 +284,7 @@ impl ImportEdit {
284 let _p = profile::span("ImportEdit::to_text_edit"); 284 let _p = profile::span("ImportEdit::to_text_edit");
285 285
286 let rewriter = 286 let rewriter =
287 insert_use::insert_use(&self.import_scope, mod_path_to_ast(&self.import_path), cfg); 287 insert_use::insert_use(&self.scope, mod_path_to_ast(&self.import.import_path), cfg);
288 let old_ast = rewriter.rewrite_root()?; 288 let old_ast = rewriter.rewrite_root()?;
289 let mut import_insert = TextEdit::builder(); 289 let mut import_insert = TextEdit::builder();
290 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert); 290 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);
@@ -308,7 +308,7 @@ pub(crate) struct Builder {
308 lookup: Option<String>, 308 lookup: Option<String>,
309 kind: Option<CompletionItemKind>, 309 kind: Option<CompletionItemKind>,
310 text_edit: Option<TextEdit>, 310 text_edit: Option<TextEdit>,
311 deprecated: Option<bool>, 311 deprecated: bool,
312 trigger_call_info: Option<bool>, 312 trigger_call_info: Option<bool>,
313 score: Option<CompletionScore>, 313 score: Option<CompletionScore>,
314 ref_match: Option<(Mutability, CompletionScore)>, 314 ref_match: Option<(Mutability, CompletionScore)>,
@@ -322,20 +322,19 @@ impl Builder {
322 let mut lookup = self.lookup; 322 let mut lookup = self.lookup;
323 let mut insert_text = self.insert_text; 323 let mut insert_text = self.insert_text;
324 324
325 if let Some(import_to_add) = self.import_to_add.as_ref() { 325 if let Some(original_path) = self
326 if import_to_add.import_for_trait_assoc_item { 326 .import_to_add
327 lookup = lookup.or_else(|| Some(label.clone())); 327 .as_ref()
328 insert_text = insert_text.or_else(|| Some(label.clone())); 328 .and_then(|import_edit| import_edit.import.original_path.as_ref())
329 label = format!("{} ({})", label, import_to_add.import_path); 329 {
330 lookup = lookup.or_else(|| Some(label.clone()));
331 insert_text = insert_text.or_else(|| Some(label.clone()));
332
333 let original_path_label = original_path.to_string();
334 if original_path_label.ends_with(&label) {
335 label = original_path_label;
330 } else { 336 } else {
331 let mut import_path_without_last_segment = import_to_add.import_path.to_owned(); 337 format_to!(label, " ({})", original_path)
332 let _ = import_path_without_last_segment.pop_segment();
333
334 if !import_path_without_last_segment.segments().is_empty() {
335 lookup = lookup.or_else(|| Some(label.clone()));
336 insert_text = insert_text.or_else(|| Some(label.clone()));
337 label = format!("{}::{}", import_path_without_last_segment, label);
338 }
339 } 338 }
340 } 339 }
341 340
@@ -356,7 +355,7 @@ impl Builder {
356 lookup, 355 lookup,
357 kind: self.kind, 356 kind: self.kind,
358 completion_kind: self.completion_kind, 357 completion_kind: self.completion_kind,
359 deprecated: self.deprecated.unwrap_or(false), 358 deprecated: self.deprecated,
360 trigger_call_info: self.trigger_call_info.unwrap_or(false), 359 trigger_call_info: self.trigger_call_info.unwrap_or(false),
361 score: self.score, 360 score: self.score,
362 ref_match: self.ref_match, 361 ref_match: self.ref_match,
@@ -416,7 +415,7 @@ impl Builder {
416 self 415 self
417 } 416 }
418 pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder { 417 pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder {
419 self.deprecated = Some(deprecated); 418 self.deprecated = deprecated;
420 self 419 self
421 } 420 }
422 pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder { 421 pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder {
@@ -431,17 +430,8 @@ impl Builder {
431 self.import_to_add = import_to_add; 430 self.import_to_add = import_to_add;
432 self 431 self
433 } 432 }
434 pub(crate) fn set_ref_match( 433 pub(crate) fn ref_match(mut self, ref_match: (Mutability, CompletionScore)) -> Builder {
435 mut self, 434 self.ref_match = Some(ref_match);
436 ref_match: Option<(Mutability, CompletionScore)>,
437 ) -> Builder {
438 self.ref_match = ref_match;
439 self 435 self
440 } 436 }
441} 437}
442
443impl<'a> Into<CompletionItem> for Builder {
444 fn into(self) -> CompletionItem {
445 self.build()
446 }
447}
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index b0b809791..a0c8c374d 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -13,7 +13,9 @@ mod completions;
13 13
14use completions::flyimport::position_for_import; 14use completions::flyimport::position_for_import;
15use ide_db::{ 15use ide_db::{
16 base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase, 16 base_db::FilePosition,
17 helpers::{import_assets::LocatedImport, insert_use::ImportScope},
18 items_locator, RootDatabase,
17}; 19};
18use text_edit::TextEdit; 20use text_edit::TextEdit;
19 21
@@ -139,25 +141,27 @@ pub fn resolve_completion_edits(
139 position: FilePosition, 141 position: FilePosition,
140 full_import_path: &str, 142 full_import_path: &str,
141 imported_name: String, 143 imported_name: String,
142 import_for_trait_assoc_item: bool,
143) -> Option<Vec<TextEdit>> { 144) -> Option<Vec<TextEdit>> {
144 let ctx = CompletionContext::new(db, position, config)?; 145 let ctx = CompletionContext::new(db, position, config)?;
145 let position_for_import = position_for_import(&ctx, None)?; 146 let position_for_import = position_for_import(&ctx, None)?;
146 let import_scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?; 147 let scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?;
147 148
148 let current_module = ctx.sema.scope(position_for_import).module()?; 149 let current_module = ctx.sema.scope(position_for_import).module()?;
149 let current_crate = current_module.krate(); 150 let current_crate = current_module.krate();
150 151
151 let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) 152 let (import_path, item_to_import) =
152 .filter_map(|candidate| { 153 items_locator::with_exact_name(&ctx.sema, current_crate, imported_name)
153 let item: hir::ItemInNs = candidate.either(Into::into, Into::into); 154 .into_iter()
154 current_module.find_use_path_prefixed(db, item, config.insert_use.prefix_kind) 155 .filter_map(|candidate| {
155 }) 156 current_module
156 .find(|mod_path| mod_path.to_string() == full_import_path)?; 157 .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
158 .zip(Some(candidate))
159 })
160 .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?;
161 let import =
162 LocatedImport::new(import_path.clone(), item_to_import, item_to_import, Some(import_path));
157 163
158 ImportEdit { import_path, import_scope, import_for_trait_assoc_item } 164 ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit])
159 .to_text_edit(config.insert_use)
160 .map(|edit| vec![edit])
161} 165}
162 166
163#[cfg(test)] 167#[cfg(test)]
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index eddaaa6f3..0a6ac8804 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -13,9 +13,11 @@ mod builder_ext;
13use hir::{ 13use hir::{
14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, 14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type,
15}; 15};
16use ide_db::{helpers::SnippetCap, RootDatabase, SymbolKind}; 16use ide_db::{
17 helpers::{item_name, SnippetCap},
18 RootDatabase, SymbolKind,
19};
17use syntax::TextRange; 20use syntax::TextRange;
18use test_utils::mark;
19 21
20use crate::{ 22use crate::{
21 item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, 23 item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
@@ -51,18 +53,20 @@ pub(crate) fn render_resolution<'a>(
51pub(crate) fn render_resolution_with_import<'a>( 53pub(crate) fn render_resolution_with_import<'a>(
52 ctx: RenderContext<'a>, 54 ctx: RenderContext<'a>,
53 import_edit: ImportEdit, 55 import_edit: ImportEdit,
54 resolution: &ScopeDef,
55) -> Option<CompletionItem> { 56) -> Option<CompletionItem> {
57 let resolution = ScopeDef::from(import_edit.import.original_item);
56 let local_name = match resolution { 58 let local_name = match resolution {
57 ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), 59 ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(),
58 ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), 60 ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(),
59 ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), 61 ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(),
60 _ => import_edit.import_path.segments().last()?.to_string(), 62 _ => item_name(ctx.db(), import_edit.import.original_item)?.to_string(),
61 }; 63 };
62 Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| { 64 Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map(
63 item.completion_kind = CompletionKind::Magic; 65 |mut item| {
64 item 66 item.completion_kind = CompletionKind::Magic;
65 }) 67 item
68 },
69 )
66} 70}
67 71
68/// Interface for data and methods required for items rendering. 72/// Interface for data and methods required for items rendering.
@@ -115,11 +119,11 @@ impl<'a> RenderContext<'a> {
115 119
116 fn active_name_and_type(&self) -> Option<(String, Type)> { 120 fn active_name_and_type(&self) -> Option<(String, Type)> {
117 if let Some(record_field) = &self.completion.record_field_syntax { 121 if let Some(record_field) = &self.completion.record_field_syntax {
118 mark::hit!(record_field_type_match); 122 cov_mark::hit!(record_field_type_match);
119 let (struct_field, _local) = self.completion.sema.resolve_record_field(record_field)?; 123 let (struct_field, _local) = self.completion.sema.resolve_record_field(record_field)?;
120 Some((struct_field.name(self.db()).to_string(), struct_field.signature_ty(self.db()))) 124 Some((struct_field.name(self.db()).to_string(), struct_field.signature_ty(self.db())))
121 } else if let Some(active_parameter) = &self.completion.active_parameter { 125 } else if let Some(active_parameter) = &self.completion.active_parameter {
122 mark::hit!(active_param_type_match); 126 cov_mark::hit!(active_param_type_match);
123 Some((active_parameter.name.clone(), active_parameter.ty.clone())) 127 Some((active_parameter.name.clone(), active_parameter.ty.clone()))
124 } else { 128 } else {
125 None 129 None
@@ -242,7 +246,6 @@ impl<'a> Render<'a> {
242 } 246 }
243 }; 247 };
244 248
245 let mut ref_match = None;
246 if let ScopeDef::Local(local) = resolution { 249 if let ScopeDef::Local(local) = resolution {
247 if let Some((active_name, active_type)) = self.ctx.active_name_and_type() { 250 if let Some((active_name, active_type)) = self.ctx.active_name_and_type() {
248 let ty = local.ty(self.ctx.db()); 251 let ty = local.ty(self.ctx.db());
@@ -251,7 +254,11 @@ impl<'a> Render<'a> {
251 { 254 {
252 item = item.set_score(score); 255 item = item.set_score(score);
253 } 256 }
254 ref_match = refed_type_matches(&active_type, &active_name, &ty, &local_name); 257 if let Some(ref_match) =
258 refed_type_matches(&active_type, &active_name, &ty, &local_name)
259 {
260 item = item.ref_match(ref_match);
261 }
255 } 262 }
256 } 263 }
257 264
@@ -269,7 +276,7 @@ impl<'a> Render<'a> {
269 _ => false, 276 _ => false,
270 }; 277 };
271 if has_non_default_type_params { 278 if has_non_default_type_params {
272 mark::hit!(inserts_angle_brackets_for_generics); 279 cov_mark::hit!(inserts_angle_brackets_for_generics);
273 item = item 280 item = item
274 .lookup_by(local_name.clone()) 281 .lookup_by(local_name.clone())
275 .label(format!("{}<…>", local_name)) 282 .label(format!("{}<…>", local_name))
@@ -281,7 +288,6 @@ impl<'a> Render<'a> {
281 Some( 288 Some(
282 item.kind(kind) 289 item.kind(kind)
283 .add_import(import_to_add) 290 .add_import(import_to_add)
284 .set_ref_match(ref_match)
285 .set_documentation(self.docs(resolution)) 291 .set_documentation(self.docs(resolution))
286 .set_deprecated(self.is_deprecated(resolution)) 292 .set_deprecated(self.is_deprecated(resolution))
287 .build(), 293 .build(),
@@ -358,7 +364,6 @@ mod tests {
358 use std::cmp::Reverse; 364 use std::cmp::Reverse;
359 365
360 use expect_test::{expect, Expect}; 366 use expect_test::{expect, Expect};
361 use test_utils::mark;
362 367
363 use crate::{ 368 use crate::{
364 test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, 369 test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG},
@@ -734,7 +739,7 @@ fn foo(s: S) { s.$0 }
734 739
735 #[test] 740 #[test]
736 fn no_call_parens_if_fn_ptr_needed() { 741 fn no_call_parens_if_fn_ptr_needed() {
737 mark::check!(no_call_parens_if_fn_ptr_needed); 742 cov_mark::check!(no_call_parens_if_fn_ptr_needed);
738 check_edit( 743 check_edit(
739 "foo", 744 "foo",
740 r#" 745 r#"
@@ -758,7 +763,7 @@ fn main() -> ManualVtable {
758 763
759 #[test] 764 #[test]
760 fn no_parens_in_use_item() { 765 fn no_parens_in_use_item() {
761 mark::check!(no_parens_in_use_item); 766 cov_mark::check!(no_parens_in_use_item);
762 check_edit( 767 check_edit(
763 "foo", 768 "foo",
764 r#" 769 r#"
@@ -802,7 +807,7 @@ fn f(foo: &Foo) { foo.foo(); }
802 807
803 #[test] 808 #[test]
804 fn inserts_angle_brackets_for_generics() { 809 fn inserts_angle_brackets_for_generics() {
805 mark::check!(inserts_angle_brackets_for_generics); 810 cov_mark::check!(inserts_angle_brackets_for_generics);
806 check_edit( 811 check_edit(
807 "Vec", 812 "Vec",
808 r#" 813 r#"
@@ -851,7 +856,7 @@ fn foo(xs: Vec<i128>)
851 856
852 #[test] 857 #[test]
853 fn active_param_score() { 858 fn active_param_score() {
854 mark::check!(active_param_type_match); 859 cov_mark::check!(active_param_type_match);
855 check_scores( 860 check_scores(
856 r#" 861 r#"
857struct S { foo: i64, bar: u32, baz: u32 } 862struct S { foo: i64, bar: u32, baz: u32 }
@@ -868,7 +873,7 @@ fn foo(s: S) { test(s.$0) }
868 873
869 #[test] 874 #[test]
870 fn record_field_scores() { 875 fn record_field_scores() {
871 mark::check!(record_field_type_match); 876 cov_mark::check!(record_field_type_match);
872 check_scores( 877 check_scores(
873 r#" 878 r#"
874struct A { foo: i64, bar: u32, baz: u32 } 879struct A { foo: i64, bar: u32, baz: u32 }
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs
index d053a988b..95a7596c1 100644
--- a/crates/ide_completion/src/render/builder_ext.rs
+++ b/crates/ide_completion/src/render/builder_ext.rs
@@ -1,7 +1,6 @@
1//! Extensions for `Builder` structure required for item rendering. 1//! Extensions for `Builder` structure required for item rendering.
2 2
3use itertools::Itertools; 3use itertools::Itertools;
4use test_utils::mark;
5 4
6use crate::{item::Builder, CompletionContext}; 5use crate::{item::Builder, CompletionContext};
7 6
@@ -30,7 +29,7 @@ impl Builder {
30 return false; 29 return false;
31 } 30 }
32 if ctx.use_item_syntax.is_some() { 31 if ctx.use_item_syntax.is_some() {
33 mark::hit!(no_parens_in_use_item); 32 cov_mark::hit!(no_parens_in_use_item);
34 return false; 33 return false;
35 } 34 }
36 if ctx.is_pattern_call { 35 if ctx.is_pattern_call {
@@ -43,7 +42,7 @@ impl Builder {
43 // Don't add parentheses if the expected type is some function reference. 42 // Don't add parentheses if the expected type is some function reference.
44 if let Some(ty) = &ctx.expected_type { 43 if let Some(ty) = &ctx.expected_type {
45 if ty.is_fn() { 44 if ty.is_fn() {
46 mark::hit!(no_call_parens_if_fn_ptr_needed); 45 cov_mark::hit!(no_call_parens_if_fn_ptr_needed);
47 return false; 46 return false;
48 } 47 }
49 } 48 }
@@ -67,7 +66,7 @@ impl Builder {
67 None => return self, 66 None => return self,
68 }; 67 };
69 // If not an import, add parenthesis automatically. 68 // If not an import, add parenthesis automatically.
70 mark::hit!(inserts_parens_for_function_calls); 69 cov_mark::hit!(inserts_parens_for_function_calls);
71 70
72 let (snippet, label) = if params.is_empty() { 71 let (snippet, label) = if params.is_empty() {
73 (format!("{}()$0", name), format!("{}()", name)) 72 (format!("{}()$0", name), format!("{}()", name))
@@ -82,7 +81,7 @@ impl Builder {
82 format!("{}({})$0", name, function_params_snippet) 81 format!("{}({})$0", name, function_params_snippet)
83 } 82 }
84 _ => { 83 _ => {
85 mark::hit!(suppress_arg_snippets); 84 cov_mark::hit!(suppress_arg_snippets);
86 format!("{}($0)", name) 85 format!("{}($0)", name)
87 } 86 }
88 }; 87 };
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs
index 9214193b4..ed055c1fb 100644
--- a/crates/ide_completion/src/render/enum_variant.rs
+++ b/crates/ide_completion/src/render/enum_variant.rs
@@ -3,7 +3,6 @@
3use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; 3use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
4use ide_db::SymbolKind; 4use ide_db::SymbolKind;
5use itertools::Itertools; 5use itertools::Itertools;
6use test_utils::mark;
7 6
8use crate::{ 7use crate::{
9 item::{CompletionItem, CompletionKind, ImportEdit}, 8 item::{CompletionItem, CompletionKind, ImportEdit},
@@ -68,7 +67,7 @@ impl<'a> EnumRender<'a> {
68 .detail(self.detail()); 67 .detail(self.detail());
69 68
70 if self.variant_kind == StructKind::Tuple { 69 if self.variant_kind == StructKind::Tuple {
71 mark::hit!(inserts_parens_for_tuple_enums); 70 cov_mark::hit!(inserts_parens_for_tuple_enums);
72 let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len()); 71 let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len());
73 builder = 72 builder =
74 builder.add_call_parens(self.ctx.completion, self.short_qualified_name, params); 73 builder.add_call_parens(self.ctx.completion, self.short_qualified_name, params);
@@ -103,13 +102,11 @@ impl<'a> EnumRender<'a> {
103 102
104#[cfg(test)] 103#[cfg(test)]
105mod tests { 104mod tests {
106 use test_utils::mark;
107
108 use crate::test_utils::check_edit; 105 use crate::test_utils::check_edit;
109 106
110 #[test] 107 #[test]
111 fn inserts_parens_for_tuple_enums() { 108 fn inserts_parens_for_tuple_enums() {
112 mark::check!(inserts_parens_for_tuple_enums); 109 cov_mark::check!(inserts_parens_for_tuple_enums);
113 check_edit( 110 check_edit(
114 "Some", 111 "Some",
115 r#" 112 r#"
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index e46e21d24..5931945a8 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -3,7 +3,6 @@
3use hir::{HasSource, HirDisplay, Type}; 3use hir::{HasSource, HirDisplay, Type};
4use ide_db::SymbolKind; 4use ide_db::SymbolKind;
5use syntax::ast::Fn; 5use syntax::ast::Fn;
6use test_utils::mark;
7 6
8use crate::{ 7use crate::{
9 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, 8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
@@ -82,7 +81,7 @@ impl<'a> FunctionRender<'a> {
82 self.func.method_params(self.ctx.db()).unwrap_or_default() 81 self.func.method_params(self.ctx.db()).unwrap_or_default()
83 } else { 82 } else {
84 if let Some(s) = ast_params.self_param() { 83 if let Some(s) = ast_params.self_param() {
85 mark::hit!(parens_for_method_call_as_assoc_fn); 84 cov_mark::hit!(parens_for_method_call_as_assoc_fn);
86 params_pats.push(Some(s.to_string())); 85 params_pats.push(Some(s.to_string()));
87 } 86 }
88 self.func.assoc_fn_params(self.ctx.db()) 87 self.func.assoc_fn_params(self.ctx.db())
@@ -114,8 +113,6 @@ impl<'a> FunctionRender<'a> {
114 113
115#[cfg(test)] 114#[cfg(test)]
116mod tests { 115mod tests {
117 use test_utils::mark;
118
119 use crate::{ 116 use crate::{
120 test_utils::{check_edit, check_edit_with_config, TEST_CONFIG}, 117 test_utils::{check_edit, check_edit_with_config, TEST_CONFIG},
121 CompletionConfig, 118 CompletionConfig,
@@ -123,7 +120,7 @@ mod tests {
123 120
124 #[test] 121 #[test]
125 fn inserts_parens_for_function_calls() { 122 fn inserts_parens_for_function_calls() {
126 mark::check!(inserts_parens_for_function_calls); 123 cov_mark::check!(inserts_parens_for_function_calls);
127 check_edit( 124 check_edit(
128 "no_args", 125 "no_args",
129 r#" 126 r#"
@@ -191,7 +188,7 @@ fn bar(s: &S) {
191 188
192 #[test] 189 #[test]
193 fn parens_for_method_call_as_assoc_fn() { 190 fn parens_for_method_call_as_assoc_fn() {
194 mark::check!(parens_for_method_call_as_assoc_fn); 191 cov_mark::check!(parens_for_method_call_as_assoc_fn);
195 check_edit( 192 check_edit(
196 "foo", 193 "foo",
197 r#" 194 r#"
@@ -213,7 +210,7 @@ fn main() { S::foo(${1:&self})$0 }
213 210
214 #[test] 211 #[test]
215 fn suppress_arg_snippets() { 212 fn suppress_arg_snippets() {
216 mark::check!(suppress_arg_snippets); 213 cov_mark::check!(suppress_arg_snippets);
217 check_edit_with_config( 214 check_edit_with_config(
218 CompletionConfig { add_call_argument_snippets: false, ..TEST_CONFIG }, 215 CompletionConfig { add_call_argument_snippets: false, ..TEST_CONFIG },
219 "with_args", 216 "with_args",
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index a4535786f..a6cf3e479 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -3,7 +3,6 @@
3use hir::{Documentation, HasSource}; 3use hir::{Documentation, HasSource};
4use ide_db::SymbolKind; 4use ide_db::SymbolKind;
5use syntax::display::macro_label; 5use syntax::display::macro_label;
6use test_utils::mark;
7 6
8use crate::{ 7use crate::{
9 item::{CompletionItem, CompletionKind, ImportEdit}, 8 item::{CompletionItem, CompletionKind, ImportEdit},
@@ -57,7 +56,7 @@ impl<'a> MacroRender<'a> {
57 } 56 }
58 None if needs_bang => builder.insert_text(self.banged_name()), 57 None if needs_bang => builder.insert_text(self.banged_name()),
59 _ => { 58 _ => {
60 mark::hit!(dont_insert_macro_call_parens_unncessary); 59 cov_mark::hit!(dont_insert_macro_call_parens_unncessary);
61 builder.insert_text(&self.name) 60 builder.insert_text(&self.name)
62 } 61 }
63 }; 62 };
@@ -125,13 +124,11 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s
125 124
126#[cfg(test)] 125#[cfg(test)]
127mod tests { 126mod tests {
128 use test_utils::mark;
129
130 use crate::test_utils::check_edit; 127 use crate::test_utils::check_edit;
131 128
132 #[test] 129 #[test]
133 fn dont_insert_macro_call_parens_unncessary() { 130 fn dont_insert_macro_call_parens_unncessary() {
134 mark::check!(dont_insert_macro_call_parens_unncessary); 131 cov_mark::check!(dont_insert_macro_call_parens_unncessary);
135 check_edit( 132 check_edit(
136 "frobnicate!", 133 "frobnicate!",
137 r#" 134 r#"