diff options
Diffstat (limited to 'crates/ide_completion/src/completions')
-rw-r--r-- | crates/ide_completion/src/completions/attribute.rs | 38 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/dot.rs | 6 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 280 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/fn_param.rs | 26 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 85 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/mod_.rs | 6 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/postfix.rs | 21 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/qualified_path.rs | 18 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/record.rs | 15 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/snippet.rs | 25 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/trait_impl.rs | 32 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 12 |
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 | ||
41 | fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) { | 41 | fn 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 | ||
3 | use hir::{HasVisibility, Type}; | 3 | use hir::{HasVisibility, Type}; |
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | use test_utils::mark; | ||
6 | 5 | ||
7 | use crate::{context::CompletionContext, Completions}; | 6 | use 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)] |
63 | mod tests { | 62 | mod 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#" |
128 | struct A { the_field: u32 } | 126 | struct 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 | ||
51 | use hir::{AsAssocItem, ModPath, ScopeDef}; | 91 | use hir::ModPath; |
52 | use ide_db::helpers::{ | 92 | use ide_db::helpers::{ |
53 | import_assets::{ImportAssets, ImportCandidate}, | 93 | import_assets::{ImportAssets, ImportCandidate}, |
54 | insert_use::ImportScope, | 94 | insert_use::ImportScope, |
55 | }; | 95 | }; |
56 | use rustc_hash::FxHashSet; | 96 | use itertools::Itertools; |
57 | use syntax::{AstNode, SyntaxNode, T}; | 97 | use syntax::{AstNode, SyntaxNode, T}; |
58 | use test_utils::mark; | ||
59 | 98 | ||
60 | use crate::{ | 99 | use 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 | ||
132 | fn 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 | |||
140 | pub(crate) fn position_for_import<'a>( | 155 | pub(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)] |
201 | mod tests { | 223 | mod 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#" | ||
803 | mod foo { | ||
804 | pub mod bar { | ||
805 | pub mod baz { | ||
806 | pub struct Item; | ||
807 | } | ||
808 | } | ||
809 | } | ||
810 | |||
811 | fn 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#" | ||
845 | mod foo { | ||
846 | pub struct Item; | ||
847 | |||
848 | impl Item { | ||
849 | pub const TEST_ASSOC: usize = 3; | ||
850 | } | ||
851 | } | ||
852 | |||
853 | fn 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#" | ||
868 | use foo::Item; | ||
869 | |||
870 | mod foo { | ||
871 | pub struct Item; | ||
872 | |||
873 | impl Item { | ||
874 | pub const TEST_ASSOC: usize = 3; | ||
875 | } | ||
876 | } | ||
877 | |||
878 | fn main() { | ||
879 | Item::TEST_ASSOC | ||
880 | }"#, | ||
881 | ); | ||
882 | } | ||
883 | |||
884 | #[test] | ||
885 | fn unresolved_assoc_item_container_with_path() { | ||
886 | let fixture = r#" | ||
887 | mod foo { | ||
888 | pub mod bar { | ||
889 | pub struct Item; | ||
890 | |||
891 | impl Item { | ||
892 | pub const TEST_ASSOC: usize = 3; | ||
893 | } | ||
894 | } | ||
895 | } | ||
896 | |||
897 | fn 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#" | ||
912 | use foo::bar; | ||
913 | |||
914 | mod foo { | ||
915 | pub mod bar { | ||
916 | pub struct Item; | ||
917 | |||
918 | impl Item { | ||
919 | pub const TEST_ASSOC: usize = 3; | ||
920 | } | ||
921 | } | ||
922 | } | ||
923 | |||
924 | fn main() { | ||
925 | bar::Item::TEST_ASSOC | ||
926 | }"#, | ||
927 | ); | ||
928 | } | ||
929 | |||
930 | #[test] | ||
931 | fn fuzzy_unresolved_path() { | ||
932 | check( | ||
933 | r#" | ||
934 | mod foo { | ||
935 | pub mod bar { | ||
936 | pub struct Item; | ||
937 | |||
938 | impl Item { | ||
939 | pub const TEST_ASSOC: usize = 3; | ||
940 | } | ||
941 | } | ||
942 | } | ||
943 | |||
944 | fn 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 | ||
3 | use std::iter; | ||
4 | |||
3 | use syntax::SyntaxKind; | 5 | use syntax::SyntaxKind; |
4 | use test_utils::mark; | ||
5 | 6 | ||
6 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; | 7 | use 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 | ||
42 | pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 44 | pub(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 | ||
161 | fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) { | 164 | fn 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)] |
182 | mod tests { | 188 | mod 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#" |
481 | fn test() { | 498 | fn 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#" |
585 | struct Foo { | 603 | struct 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 @@ | |||
3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; | 3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; |
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | use syntax::AstNode; | 5 | use syntax::AstNode; |
6 | use test_utils::mark; | ||
7 | 6 | ||
8 | use crate::{CompletionContext, Completions}; | 7 | use 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)] |
162 | mod tests { | 155 | mod 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 | ||
10 | fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { | 10 | fn 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 | ||
16 | pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 16 | pub(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 { | |||
62 | fn ${1:feature}() { | 62 | fn ${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 | ||
196 | fn add_const_impl( | 195 | fn 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 | ||
3 | use hir::ScopeDef; | 3 | use hir::ScopeDef; |
4 | use syntax::AstNode; | 4 | use syntax::AstNode; |
5 | use test_utils::mark; | ||
6 | 5 | ||
7 | use crate::{CompletionContext, Completions}; | 6 | use 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)] |
49 | mod tests { | 48 | mod 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#" |
72 | use foo$0 | 70 | use 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#" |