diff options
Diffstat (limited to 'crates/ide_completion/src')
33 files changed, 2218 insertions, 1781 deletions
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index bd90cefb2..cba5eb0c6 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs | |||
@@ -41,9 +41,9 @@ pub struct Completions { | |||
41 | buf: Vec<CompletionItem>, | 41 | buf: Vec<CompletionItem>, |
42 | } | 42 | } |
43 | 43 | ||
44 | impl Into<Vec<CompletionItem>> for Completions { | 44 | impl From<Completions> for Vec<CompletionItem> { |
45 | fn into(self) -> Vec<CompletionItem> { | 45 | fn from(val: Completions) -> Self { |
46 | self.buf | 46 | val.buf |
47 | } | 47 | } |
48 | } | 48 | } |
49 | 49 | ||
@@ -74,44 +74,12 @@ impl Completions { | |||
74 | items.into_iter().for_each(|item| self.add(item.into())) | 74 | items.into_iter().for_each(|item| self.add(item.into())) |
75 | } | 75 | } |
76 | 76 | ||
77 | pub(crate) fn add_field( | ||
78 | &mut self, | ||
79 | ctx: &CompletionContext, | ||
80 | receiver: Option<hir::Name>, | ||
81 | field: hir::Field, | ||
82 | ty: &hir::Type, | ||
83 | ) { | ||
84 | let item = render_field(RenderContext::new(ctx), receiver, field, ty); | ||
85 | self.add(item); | ||
86 | } | ||
87 | |||
88 | pub(crate) fn add_tuple_field( | ||
89 | &mut self, | ||
90 | ctx: &CompletionContext, | ||
91 | receiver: Option<hir::Name>, | ||
92 | field: usize, | ||
93 | ty: &hir::Type, | ||
94 | ) { | ||
95 | let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); | ||
96 | self.add(item); | ||
97 | } | ||
98 | |||
99 | pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) { | ||
100 | let mut item = | ||
101 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static"); | ||
102 | item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam)); | ||
103 | self.add(item.build()); | ||
104 | } | ||
105 | |||
106 | pub(crate) fn add_resolution( | 77 | pub(crate) fn add_resolution( |
107 | &mut self, | 78 | &mut self, |
108 | ctx: &CompletionContext, | 79 | ctx: &CompletionContext, |
109 | local_name: hir::Name, | 80 | local_name: hir::Name, |
110 | resolution: &hir::ScopeDef, | 81 | resolution: &hir::ScopeDef, |
111 | ) { | 82 | ) { |
112 | if ctx.expects_type() && resolution.is_value_def() { | ||
113 | return; | ||
114 | } | ||
115 | self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution)); | 83 | self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution)); |
116 | } | 84 | } |
117 | 85 | ||
@@ -134,9 +102,6 @@ impl Completions { | |||
134 | func: hir::Function, | 102 | func: hir::Function, |
135 | local_name: Option<hir::Name>, | 103 | local_name: Option<hir::Name>, |
136 | ) { | 104 | ) { |
137 | if ctx.expects_type() { | ||
138 | return; | ||
139 | } | ||
140 | self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func)); | 105 | self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func)); |
141 | } | 106 | } |
142 | 107 | ||
@@ -150,94 +115,119 @@ impl Completions { | |||
150 | self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func)); | 115 | self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func)); |
151 | } | 116 | } |
152 | 117 | ||
153 | pub(crate) fn add_variant_pat( | 118 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { |
119 | self.add_opt(render_const(RenderContext::new(ctx), constant)); | ||
120 | } | ||
121 | |||
122 | pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { | ||
123 | self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); | ||
124 | } | ||
125 | |||
126 | pub(crate) fn add_type_alias_with_eq( | ||
154 | &mut self, | 127 | &mut self, |
155 | ctx: &CompletionContext, | 128 | ctx: &CompletionContext, |
156 | variant: hir::Variant, | 129 | type_alias: hir::TypeAlias, |
157 | local_name: Option<hir::Name>, | ||
158 | ) { | 130 | ) { |
159 | self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); | 131 | self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); |
160 | } | 132 | } |
161 | 133 | ||
162 | pub(crate) fn add_qualified_variant_pat( | 134 | pub(crate) fn add_qualified_enum_variant( |
163 | &mut self, | 135 | &mut self, |
164 | ctx: &CompletionContext, | 136 | ctx: &CompletionContext, |
165 | variant: hir::Variant, | 137 | variant: hir::Variant, |
166 | path: hir::ModPath, | 138 | path: hir::ModPath, |
167 | ) { | 139 | ) { |
168 | self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); | 140 | let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); |
141 | self.add(item); | ||
169 | } | 142 | } |
170 | 143 | ||
171 | pub(crate) fn add_struct_pat( | 144 | pub(crate) fn add_enum_variant( |
172 | &mut self, | 145 | &mut self, |
173 | ctx: &CompletionContext, | 146 | ctx: &CompletionContext, |
174 | strukt: hir::Struct, | 147 | variant: hir::Variant, |
175 | local_name: Option<hir::Name>, | 148 | local_name: Option<hir::Name>, |
176 | ) { | 149 | ) { |
177 | self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name)); | 150 | let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); |
151 | self.add(item); | ||
178 | } | 152 | } |
179 | 153 | ||
180 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | 154 | pub(crate) fn add_field( |
181 | if ctx.expects_type() { | 155 | &mut self, |
182 | return; | 156 | ctx: &CompletionContext, |
183 | } | 157 | receiver: Option<hir::Name>, |
184 | self.add_opt(render_const(RenderContext::new(ctx), constant)); | 158 | field: hir::Field, |
159 | ty: &hir::Type, | ||
160 | ) { | ||
161 | let item = render_field(RenderContext::new(ctx), receiver, field, ty); | ||
162 | self.add(item); | ||
185 | } | 163 | } |
186 | 164 | ||
187 | pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { | 165 | pub(crate) fn add_tuple_field( |
188 | self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); | 166 | &mut self, |
167 | ctx: &CompletionContext, | ||
168 | receiver: Option<hir::Name>, | ||
169 | field: usize, | ||
170 | ty: &hir::Type, | ||
171 | ) { | ||
172 | let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); | ||
173 | self.add(item); | ||
189 | } | 174 | } |
190 | 175 | ||
191 | pub(crate) fn add_type_alias_with_eq( | 176 | pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) { |
177 | let mut item = | ||
178 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static"); | ||
179 | item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam)); | ||
180 | self.add(item.build()); | ||
181 | } | ||
182 | |||
183 | pub(crate) fn add_variant_pat( | ||
192 | &mut self, | 184 | &mut self, |
193 | ctx: &CompletionContext, | 185 | ctx: &CompletionContext, |
194 | type_alias: hir::TypeAlias, | 186 | variant: hir::Variant, |
187 | local_name: Option<hir::Name>, | ||
195 | ) { | 188 | ) { |
196 | self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); | 189 | self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); |
197 | } | 190 | } |
198 | 191 | ||
199 | pub(crate) fn add_qualified_enum_variant( | 192 | pub(crate) fn add_qualified_variant_pat( |
200 | &mut self, | 193 | &mut self, |
201 | ctx: &CompletionContext, | 194 | ctx: &CompletionContext, |
202 | variant: hir::Variant, | 195 | variant: hir::Variant, |
203 | path: hir::ModPath, | 196 | path: hir::ModPath, |
204 | ) { | 197 | ) { |
205 | let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); | 198 | self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); |
206 | self.add(item); | ||
207 | } | 199 | } |
208 | 200 | ||
209 | pub(crate) fn add_enum_variant( | 201 | pub(crate) fn add_struct_pat( |
210 | &mut self, | 202 | &mut self, |
211 | ctx: &CompletionContext, | 203 | ctx: &CompletionContext, |
212 | variant: hir::Variant, | 204 | strukt: hir::Struct, |
213 | local_name: Option<hir::Name>, | 205 | local_name: Option<hir::Name>, |
214 | ) { | 206 | ) { |
215 | if ctx.expects_type() { | 207 | self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name)); |
216 | return; | ||
217 | } | ||
218 | let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); | ||
219 | self.add(item); | ||
220 | } | 208 | } |
221 | } | 209 | } |
222 | 210 | ||
223 | fn complete_enum_variants( | 211 | /// Calls the callback for each variant of the provided enum with the path to the variant. |
212 | /// Skips variants that are visible with single segment paths. | ||
213 | fn enum_variants_with_paths( | ||
224 | acc: &mut Completions, | 214 | acc: &mut Completions, |
225 | ctx: &CompletionContext, | 215 | ctx: &CompletionContext, |
226 | enum_data: hir::Enum, | 216 | enum_: hir::Enum, |
227 | cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), | 217 | cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), |
228 | ) { | 218 | ) { |
229 | let variants = enum_data.variants(ctx.db); | 219 | let variants = enum_.variants(ctx.db); |
230 | 220 | ||
231 | let module = if let Some(module) = ctx.scope.module() { | 221 | let module = if let Some(module) = ctx.scope.module() { |
232 | // Compute path from the completion site if available. | 222 | // Compute path from the completion site if available. |
233 | module | 223 | module |
234 | } else { | 224 | } else { |
235 | // Otherwise fall back to the enum's definition site. | 225 | // Otherwise fall back to the enum's definition site. |
236 | enum_data.module(ctx.db) | 226 | enum_.module(ctx.db) |
237 | }; | 227 | }; |
238 | 228 | ||
239 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { | 229 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { |
240 | if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_data)) { | 230 | if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) { |
241 | for &variant in &variants { | 231 | for &variant in &variants { |
242 | let self_path = hir::ModPath::from_segments( | 232 | let self_path = hir::ModPath::from_segments( |
243 | hir::PathKind::Plain, | 233 | hir::PathKind::Plain, |
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index 6df569c2a..78fc30e16 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs | |||
@@ -17,12 +17,14 @@ use crate::{ | |||
17 | 17 | ||
18 | mod derive; | 18 | mod derive; |
19 | mod lint; | 19 | mod lint; |
20 | mod repr; | ||
20 | 21 | ||
21 | pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 22 | pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
22 | let attribute = ctx.attribute_under_caret.as_ref()?; | 23 | let attribute = ctx.attribute_under_caret.as_ref()?; |
23 | match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) { | 24 | match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) { |
24 | (Some(path), Some(token_tree)) => match path.text().as_str() { | 25 | (Some(path), Some(token_tree)) => match path.text().as_str() { |
25 | "derive" => derive::complete_derive(acc, ctx, token_tree), | 26 | "derive" => derive::complete_derive(acc, ctx, token_tree), |
27 | "repr" => repr::complete_repr(acc, ctx, token_tree), | ||
26 | "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), | 28 | "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), |
27 | "allow" | "warn" | "deny" | "forbid" => { | 29 | "allow" | "warn" | "deny" | "forbid" => { |
28 | lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); | 30 | lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); |
@@ -322,7 +324,7 @@ mod tests { | |||
322 | 324 | ||
323 | use expect_test::{expect, Expect}; | 325 | use expect_test::{expect, Expect}; |
324 | 326 | ||
325 | use crate::{test_utils::completion_list, CompletionKind}; | 327 | use crate::tests::completion_list; |
326 | 328 | ||
327 | #[test] | 329 | #[test] |
328 | fn attributes_are_sorted() { | 330 | fn attributes_are_sorted() { |
@@ -341,7 +343,7 @@ mod tests { | |||
341 | } | 343 | } |
342 | 344 | ||
343 | fn check(ra_fixture: &str, expect: Expect) { | 345 | fn check(ra_fixture: &str, expect: Expect) { |
344 | let actual = completion_list(ra_fixture, CompletionKind::Attribute); | 346 | let actual = completion_list(ra_fixture); |
345 | expect.assert_eq(&actual); | 347 | expect.assert_eq(&actual); |
346 | } | 348 | } |
347 | 349 | ||
@@ -792,6 +794,7 @@ mod tests { | |||
792 | 794 | ||
793 | #[test] | 795 | #[test] |
794 | fn complete_attribute_on_expr() { | 796 | fn complete_attribute_on_expr() { |
797 | cov_mark::check!(no_keyword_completion_in_attr_of_expr); | ||
795 | check( | 798 | check( |
796 | r#"fn main() { #[$0] foo() }"#, | 799 | r#"fn main() { #[$0] foo() }"#, |
797 | expect![[r#" | 800 | expect![[r#" |
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index d526824fb..6fe41e0d6 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs | |||
@@ -31,6 +31,8 @@ pub(super) fn complete_derive( | |||
31 | let lookup = components.join(", "); | 31 | let lookup = components.join(", "); |
32 | let label = components.iter().rev().join(", "); | 32 | let label = components.iter().rev().join(", "); |
33 | (label, Some(lookup)) | 33 | (label, Some(lookup)) |
34 | } else if existing_derives.contains(&derive) { | ||
35 | continue; | ||
34 | } else { | 36 | } else { |
35 | (derive, None) | 37 | (derive, None) |
36 | }; | 38 | }; |
@@ -80,10 +82,31 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[ | |||
80 | mod tests { | 82 | mod tests { |
81 | use expect_test::{expect, Expect}; | 83 | use expect_test::{expect, Expect}; |
82 | 84 | ||
83 | use crate::{test_utils::completion_list, CompletionKind}; | 85 | use crate::tests::completion_list; |
84 | 86 | ||
85 | fn check(ra_fixture: &str, expect: Expect) { | 87 | fn check(ra_fixture: &str, expect: Expect) { |
86 | let actual = completion_list(ra_fixture, CompletionKind::Attribute); | 88 | let builtin_derives = r#" |
89 | #[rustc_builtin_macro] | ||
90 | pub macro Clone {} | ||
91 | #[rustc_builtin_macro] | ||
92 | pub macro Copy {} | ||
93 | #[rustc_builtin_macro] | ||
94 | pub macro Default {} | ||
95 | #[rustc_builtin_macro] | ||
96 | pub macro Debug {} | ||
97 | #[rustc_builtin_macro] | ||
98 | pub macro Hash {} | ||
99 | #[rustc_builtin_macro] | ||
100 | pub macro PartialEq {} | ||
101 | #[rustc_builtin_macro] | ||
102 | pub macro Eq {} | ||
103 | #[rustc_builtin_macro] | ||
104 | pub macro PartialOrd {} | ||
105 | #[rustc_builtin_macro] | ||
106 | pub macro Ord {} | ||
107 | |||
108 | "#; | ||
109 | let actual = completion_list(&format!("{} {}", builtin_derives, ra_fixture)); | ||
87 | expect.assert_eq(&actual); | 110 | expect.assert_eq(&actual); |
88 | } | 111 | } |
89 | 112 | ||
@@ -93,56 +116,53 @@ mod tests { | |||
93 | } | 116 | } |
94 | 117 | ||
95 | #[test] | 118 | #[test] |
96 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
97 | fn empty_derive() { | 119 | fn empty_derive() { |
98 | check( | 120 | check( |
99 | r#"#[derive($0)] struct Test;"#, | 121 | r#"#[derive($0)] struct Test;"#, |
100 | expect![[r#" | 122 | expect![[r#" |
101 | at Clone | 123 | at PartialEq |
102 | at Clone, Copy | 124 | at Default |
103 | at Debug | 125 | at PartialEq, Eq |
104 | at Default | 126 | at PartialEq, Eq, PartialOrd, Ord |
105 | at Hash | 127 | at Clone, Copy |
106 | at PartialEq | 128 | at Debug |
107 | at PartialEq, Eq | 129 | at Clone |
108 | at PartialEq, PartialOrd | 130 | at Hash |
109 | at PartialEq, Eq, PartialOrd, Ord | 131 | at PartialEq, PartialOrd |
110 | "#]], | 132 | "#]], |
111 | ); | 133 | ); |
112 | } | 134 | } |
113 | 135 | ||
114 | #[test] | 136 | #[test] |
115 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
116 | fn derive_with_input() { | 137 | fn derive_with_input() { |
117 | check( | 138 | check( |
118 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, | 139 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, |
119 | expect![[r#" | 140 | expect![[r#" |
120 | at Clone | 141 | at Default |
142 | at Eq | ||
143 | at Eq, PartialOrd, Ord | ||
121 | at Clone, Copy | 144 | at Clone, Copy |
122 | at Debug | 145 | at Debug |
123 | at Default | 146 | at Clone |
124 | at Hash | 147 | at Hash |
125 | at Eq | ||
126 | at PartialOrd | 148 | at PartialOrd |
127 | at Eq, PartialOrd, Ord | ||
128 | "#]], | 149 | "#]], |
129 | ) | 150 | ) |
130 | } | 151 | } |
131 | 152 | ||
132 | #[test] | 153 | #[test] |
133 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
134 | fn derive_with_input2() { | 154 | fn derive_with_input2() { |
135 | check( | 155 | check( |
136 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, | 156 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, |
137 | expect![[r#" | 157 | expect![[r#" |
138 | at Clone | 158 | at Default |
159 | at Eq | ||
160 | at Eq, PartialOrd, Ord | ||
139 | at Clone, Copy | 161 | at Clone, Copy |
140 | at Debug | 162 | at Debug |
141 | at Default | 163 | at Clone |
142 | at Hash | 164 | at Hash |
143 | at Eq | ||
144 | at PartialOrd | 165 | at PartialOrd |
145 | at Eq, PartialOrd, Ord | ||
146 | "#]], | 166 | "#]], |
147 | ) | 167 | ) |
148 | } | 168 | } |
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs index ca99e9759..1ddc38986 100644 --- a/crates/ide_completion/src/completions/attribute/lint.rs +++ b/crates/ide_completion/src/completions/attribute/lint.rs | |||
@@ -33,8 +33,7 @@ pub(super) fn complete_lint( | |||
33 | 33 | ||
34 | #[cfg(test)] | 34 | #[cfg(test)] |
35 | mod tests { | 35 | mod tests { |
36 | 36 | use crate::tests::check_edit; | |
37 | use crate::test_utils::check_edit; | ||
38 | 37 | ||
39 | #[test] | 38 | #[test] |
40 | fn check_empty() { | 39 | fn check_empty() { |
diff --git a/crates/ide_completion/src/completions/attribute/repr.rs b/crates/ide_completion/src/completions/attribute/repr.rs new file mode 100644 index 000000000..92a262a43 --- /dev/null +++ b/crates/ide_completion/src/completions/attribute/repr.rs | |||
@@ -0,0 +1,199 @@ | |||
1 | //! Completion for representations. | ||
2 | |||
3 | use syntax::ast; | ||
4 | |||
5 | use crate::{ | ||
6 | context::CompletionContext, | ||
7 | item::{CompletionItem, CompletionItemKind, CompletionKind}, | ||
8 | Completions, | ||
9 | }; | ||
10 | |||
11 | pub(super) fn complete_repr( | ||
12 | acc: &mut Completions, | ||
13 | ctx: &CompletionContext, | ||
14 | derive_input: ast::TokenTree, | ||
15 | ) { | ||
16 | if let Some(existing_reprs) = super::parse_comma_sep_input(derive_input) { | ||
17 | for repr_completion in REPR_COMPLETIONS { | ||
18 | if existing_reprs | ||
19 | .iter() | ||
20 | .any(|it| repr_completion.label == it || repr_completion.collides.contains(&&**it)) | ||
21 | { | ||
22 | continue; | ||
23 | } | ||
24 | let mut item = CompletionItem::new( | ||
25 | CompletionKind::Attribute, | ||
26 | ctx.source_range(), | ||
27 | repr_completion.label, | ||
28 | ); | ||
29 | item.kind(CompletionItemKind::Attribute); | ||
30 | if let Some(lookup) = repr_completion.lookup { | ||
31 | item.lookup_by(lookup); | ||
32 | } | ||
33 | if let Some((snippet, cap)) = repr_completion.snippet.zip(ctx.config.snippet_cap) { | ||
34 | item.insert_snippet(cap, snippet); | ||
35 | } | ||
36 | item.add_to(acc); | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | |||
41 | struct ReprCompletion { | ||
42 | label: &'static str, | ||
43 | snippet: Option<&'static str>, | ||
44 | lookup: Option<&'static str>, | ||
45 | collides: &'static [&'static str], | ||
46 | } | ||
47 | |||
48 | const fn attr(label: &'static str, collides: &'static [&'static str]) -> ReprCompletion { | ||
49 | ReprCompletion { label, snippet: None, lookup: None, collides } | ||
50 | } | ||
51 | |||
52 | #[rustfmt::skip] | ||
53 | const REPR_COMPLETIONS: &[ReprCompletion] = &[ | ||
54 | ReprCompletion { label: "align($0)", snippet: Some("align($0)"), lookup: Some("align"), collides: &["transparent", "packed"] }, | ||
55 | attr("packed", &["transparent", "align"]), | ||
56 | attr("transparent", &["C", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
57 | attr("C", &["transparent"]), | ||
58 | attr("u8", &["transparent", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
59 | attr("u16", &["transparent", "u8", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
60 | attr("u32", &["transparent", "u8", "u16", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
61 | attr("u64", &["transparent", "u8", "u16", "u32", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
62 | attr("u128", &["transparent", "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
63 | attr("usize", &["transparent", "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
64 | attr("i8", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i16", "i32", "i64", "i128", "isize"]), | ||
65 | attr("i16", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i32", "i64", "i128", "isize"]), | ||
66 | attr("i32", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i64", "i128", "isize"]), | ||
67 | attr("i64", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i128", "isize"]), | ||
68 | attr("i28", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "isize"]), | ||
69 | attr("isize", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128"]), | ||
70 | ]; | ||
71 | |||
72 | #[cfg(test)] | ||
73 | mod tests { | ||
74 | use expect_test::{expect, Expect}; | ||
75 | |||
76 | use crate::tests::completion_list; | ||
77 | |||
78 | fn check(ra_fixture: &str, expect: Expect) { | ||
79 | let actual = completion_list(ra_fixture); | ||
80 | expect.assert_eq(&actual); | ||
81 | } | ||
82 | |||
83 | #[test] | ||
84 | fn no_completion_for_incorrect_repr() { | ||
85 | check(r#"#[repr{$0)] struct Test;"#, expect![[]]) | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn empty() { | ||
90 | check( | ||
91 | r#"#[repr($0)] struct Test;"#, | ||
92 | expect![[r#" | ||
93 | at align($0) | ||
94 | at packed | ||
95 | at transparent | ||
96 | at C | ||
97 | at u8 | ||
98 | at u16 | ||
99 | at u32 | ||
100 | at u64 | ||
101 | at u128 | ||
102 | at usize | ||
103 | at i8 | ||
104 | at i16 | ||
105 | at i32 | ||
106 | at i64 | ||
107 | at i28 | ||
108 | at isize | ||
109 | "#]], | ||
110 | ); | ||
111 | } | ||
112 | |||
113 | #[test] | ||
114 | fn transparent() { | ||
115 | check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]); | ||
116 | } | ||
117 | |||
118 | #[test] | ||
119 | fn align() { | ||
120 | check( | ||
121 | r#"#[repr(align(1), $0)] struct Test;"#, | ||
122 | expect![[r#" | ||
123 | at align($0) | ||
124 | at transparent | ||
125 | at C | ||
126 | at u8 | ||
127 | at u16 | ||
128 | at u32 | ||
129 | at u64 | ||
130 | at u128 | ||
131 | at usize | ||
132 | at i8 | ||
133 | at i16 | ||
134 | at i32 | ||
135 | at i64 | ||
136 | at i28 | ||
137 | at isize | ||
138 | "#]], | ||
139 | ); | ||
140 | } | ||
141 | |||
142 | #[test] | ||
143 | fn packed() { | ||
144 | check( | ||
145 | r#"#[repr(packed, $0)] struct Test;"#, | ||
146 | expect![[r#" | ||
147 | at transparent | ||
148 | at C | ||
149 | at u8 | ||
150 | at u16 | ||
151 | at u32 | ||
152 | at u64 | ||
153 | at u128 | ||
154 | at usize | ||
155 | at i8 | ||
156 | at i16 | ||
157 | at i32 | ||
158 | at i64 | ||
159 | at i28 | ||
160 | at isize | ||
161 | "#]], | ||
162 | ); | ||
163 | } | ||
164 | |||
165 | #[test] | ||
166 | fn c() { | ||
167 | check( | ||
168 | r#"#[repr(C, $0)] struct Test;"#, | ||
169 | expect![[r#" | ||
170 | at align($0) | ||
171 | at packed | ||
172 | at u8 | ||
173 | at u16 | ||
174 | at u32 | ||
175 | at u64 | ||
176 | at u128 | ||
177 | at usize | ||
178 | at i8 | ||
179 | at i16 | ||
180 | at i32 | ||
181 | at i64 | ||
182 | at i28 | ||
183 | at isize | ||
184 | "#]], | ||
185 | ); | ||
186 | } | ||
187 | |||
188 | #[test] | ||
189 | fn prim() { | ||
190 | check( | ||
191 | r#"#[repr(usize, $0)] struct Test;"#, | ||
192 | expect![[r#" | ||
193 | at align($0) | ||
194 | at packed | ||
195 | at C | ||
196 | "#]], | ||
197 | ); | ||
198 | } | ||
199 | } | ||
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 9552875c1..286d7cb67 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -101,10 +101,10 @@ fn complete_methods( | |||
101 | mod tests { | 101 | mod tests { |
102 | use expect_test::{expect, Expect}; | 102 | use expect_test::{expect, Expect}; |
103 | 103 | ||
104 | use crate::{test_utils::completion_list, CompletionKind}; | 104 | use crate::{tests::filtered_completion_list, CompletionKind}; |
105 | 105 | ||
106 | fn check(ra_fixture: &str, expect: Expect) { | 106 | fn check(ra_fixture: &str, expect: Expect) { |
107 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 107 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); |
108 | expect.assert_eq(&actual); | 108 | expect.assert_eq(&actual); |
109 | } | 109 | } |
110 | 110 | ||
@@ -498,10 +498,7 @@ mod foo { | |||
498 | fn issue_8931() { | 498 | fn issue_8931() { |
499 | check( | 499 | check( |
500 | r#" | 500 | r#" |
501 | #[lang = "fn_once"] | 501 | //- minicore: fn |
502 | trait FnOnce<Args> { | ||
503 | type Output; | ||
504 | } | ||
505 | struct S; | 502 | struct S; |
506 | 503 | ||
507 | struct Foo; | 504 | struct Foo; |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 30b8d44bd..814c15653 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -109,7 +109,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) | |||
109 | if !ctx.config.enable_imports_on_the_fly { | 109 | if !ctx.config.enable_imports_on_the_fly { |
110 | return None; | 110 | return None; |
111 | } | 111 | } |
112 | if ctx.use_item_syntax.is_some() | 112 | if ctx.in_use_tree() |
113 | || ctx.is_path_disallowed() | 113 | || ctx.is_path_disallowed() |
114 | || ctx.expects_item() | 114 | || ctx.expects_item() |
115 | || ctx.expects_assoc_item() | 115 | || ctx.expects_assoc_item() |
@@ -227,11 +227,11 @@ mod tests { | |||
227 | 227 | ||
228 | use crate::{ | 228 | use crate::{ |
229 | item::CompletionKind, | 229 | item::CompletionKind, |
230 | test_utils::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG}, | 230 | tests::{check_edit, check_edit_with_config, filtered_completion_list, TEST_CONFIG}, |
231 | }; | 231 | }; |
232 | 232 | ||
233 | fn check(ra_fixture: &str, expect: Expect) { | 233 | fn check(ra_fixture: &str, expect: Expect) { |
234 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | 234 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); |
235 | expect.assert_eq(&actual); | 235 | expect.assert_eq(&actual); |
236 | } | 236 | } |
237 | 237 | ||
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs index cb90e8a3e..c9f0e2473 100644 --- a/crates/ide_completion/src/completions/fn_param.rs +++ b/crates/ide_completion/src/completions/fn_param.rs | |||
@@ -64,10 +64,10 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) | |||
64 | mod tests { | 64 | mod tests { |
65 | use expect_test::{expect, Expect}; | 65 | use expect_test::{expect, Expect}; |
66 | 66 | ||
67 | use crate::{test_utils::completion_list, CompletionKind}; | 67 | use crate::{tests::filtered_completion_list, CompletionKind}; |
68 | 68 | ||
69 | fn check(ra_fixture: &str, expect: Expect) { | 69 | fn check(ra_fixture: &str, expect: Expect) { |
70 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | 70 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); |
71 | expect.assert_eq(&actual); | 71 | expect.assert_eq(&actual); |
72 | } | 72 | } |
73 | 73 | ||
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index ba13d3707..407f796ef 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -18,26 +18,22 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
18 | item | 18 | item |
19 | }; | 19 | }; |
20 | 20 | ||
21 | if ctx.use_item_syntax.is_some() { | 21 | if ctx.in_use_tree() { |
22 | let qual = ctx.path_qual(); | 22 | match &ctx.path_context { |
23 | if qual.is_none() { | 23 | Some(PathCompletionContext { qualifier: Some(qual), use_tree_parent, .. }) => { |
24 | kw_completion("crate::").add_to(acc); | 24 | if iter::successors(Some(qual.clone()), |p| p.qualifier()) |
25 | } | 25 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) |
26 | kw_completion("self").add_to(acc); | 26 | { |
27 | if iter::successors(qual.cloned(), |p| p.qualifier()) | 27 | kw_completion("super::").add_to(acc); |
28 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) | 28 | } |
29 | { | 29 | if *use_tree_parent { |
30 | kw_completion("super::").add_to(acc); | 30 | kw_completion("self").add_to(acc); |
31 | } | 31 | } |
32 | } | 32 | } |
33 | 33 | _ => { | |
34 | // Suggest .await syntax for types that implement Future trait | 34 | kw_completion("crate::").add_to(acc); |
35 | if let Some(receiver) = ctx.dot_receiver() { | 35 | kw_completion("self::").add_to(acc); |
36 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | 36 | kw_completion("super::").add_to(acc); |
37 | if ty.impls_future(ctx.db) { | ||
38 | let mut item = kw_completion("await"); | ||
39 | item.detail("expr.await"); | ||
40 | item.add_to(acc); | ||
41 | } | 37 | } |
42 | }; | 38 | }; |
43 | } | 39 | } |
@@ -52,6 +48,23 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
52 | cov_mark::hit!(no_keyword_completion_in_record_lit); | 48 | cov_mark::hit!(no_keyword_completion_in_record_lit); |
53 | return; | 49 | return; |
54 | } | 50 | } |
51 | if ctx.attribute_under_caret.is_some() { | ||
52 | cov_mark::hit!(no_keyword_completion_in_attr_of_expr); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | // Suggest .await syntax for types that implement Future trait | ||
57 | if let Some(receiver) = ctx.dot_receiver() { | ||
58 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | ||
59 | if ty.impls_future(ctx.db) { | ||
60 | let mut item = | ||
61 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await"); | ||
62 | item.kind(CompletionItemKind::Keyword).detail("expr.await"); | ||
63 | item.add_to(acc); | ||
64 | } | ||
65 | }; | ||
66 | } | ||
67 | |||
55 | let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); | 68 | let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); |
56 | 69 | ||
57 | let expects_assoc_item = ctx.expects_assoc_item(); | 70 | let expects_assoc_item = ctx.expects_assoc_item(); |
@@ -60,6 +73,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
60 | 73 | ||
61 | if ctx.has_impl_or_trait_prev_sibling() { | 74 | if ctx.has_impl_or_trait_prev_sibling() { |
62 | add_keyword("where", "where "); | 75 | add_keyword("where", "where "); |
76 | if ctx.has_impl_prev_sibling() { | ||
77 | add_keyword("for", "for "); | ||
78 | } | ||
63 | return; | 79 | return; |
64 | } | 80 | } |
65 | if ctx.previous_token_is(T![unsafe]) { | 81 | if ctx.previous_token_is(T![unsafe]) { |
@@ -75,7 +91,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
75 | return; | 91 | return; |
76 | } | 92 | } |
77 | 93 | ||
78 | if expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field() { | 94 | if !ctx.has_visibility_prev_sibling() |
95 | && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field()) | ||
96 | { | ||
79 | add_keyword("pub(crate)", "pub(crate) "); | 97 | add_keyword("pub(crate)", "pub(crate) "); |
80 | add_keyword("pub", "pub "); | 98 | add_keyword("pub", "pub "); |
81 | } | 99 | } |
@@ -88,11 +106,13 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
88 | } | 106 | } |
89 | 107 | ||
90 | if expects_item || has_block_expr_parent { | 108 | if expects_item || has_block_expr_parent { |
109 | if !ctx.has_visibility_prev_sibling() { | ||
110 | add_keyword("impl", "impl $1 {\n $0\n}"); | ||
111 | add_keyword("extern", "extern $0"); | ||
112 | } | ||
91 | add_keyword("use", "use $0"); | 113 | add_keyword("use", "use $0"); |
92 | add_keyword("impl", "impl $1 {\n $0\n}"); | ||
93 | add_keyword("trait", "trait $1 {\n $0\n}"); | 114 | add_keyword("trait", "trait $1 {\n $0\n}"); |
94 | add_keyword("static", "static $0"); | 115 | add_keyword("static", "static $0"); |
95 | add_keyword("extern", "extern $0"); | ||
96 | add_keyword("mod", "mod $0"); | 116 | add_keyword("mod", "mod $0"); |
97 | } | 117 | } |
98 | 118 | ||
@@ -102,6 +122,10 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
102 | add_keyword("union", "union $1 {\n $0\n}"); | 122 | add_keyword("union", "union $1 {\n $0\n}"); |
103 | } | 123 | } |
104 | 124 | ||
125 | if ctx.expects_type() { | ||
126 | return; | ||
127 | } | ||
128 | |||
105 | if ctx.expects_expression() { | 129 | if ctx.expects_expression() { |
106 | if !has_block_expr_parent { | 130 | if !has_block_expr_parent { |
107 | add_keyword("unsafe", "unsafe {\n $0\n}"); | 131 | add_keyword("unsafe", "unsafe {\n $0\n}"); |
@@ -186,75 +210,16 @@ mod tests { | |||
186 | use expect_test::{expect, Expect}; | 210 | use expect_test::{expect, Expect}; |
187 | 211 | ||
188 | use crate::{ | 212 | use crate::{ |
189 | test_utils::{check_edit, completion_list}, | 213 | tests::{check_edit, filtered_completion_list}, |
190 | CompletionKind, | 214 | CompletionKind, |
191 | }; | 215 | }; |
192 | 216 | ||
193 | fn check(ra_fixture: &str, expect: Expect) { | 217 | fn check(ra_fixture: &str, expect: Expect) { |
194 | let actual = completion_list(ra_fixture, CompletionKind::Keyword); | 218 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Keyword); |
195 | expect.assert_eq(&actual) | 219 | expect.assert_eq(&actual) |
196 | } | 220 | } |
197 | 221 | ||
198 | #[test] | 222 | #[test] |
199 | fn test_keywords_in_use_stmt() { | ||
200 | check( | ||
201 | r"use $0", | ||
202 | expect![[r#" | ||
203 | kw crate:: | ||
204 | kw self | ||
205 | kw super:: | ||
206 | "#]], | ||
207 | ); | ||
208 | |||
209 | // FIXME: `self` shouldn't be shown here and the check below | ||
210 | check( | ||
211 | r"use a::$0", | ||
212 | expect![[r#" | ||
213 | kw self | ||
214 | "#]], | ||
215 | ); | ||
216 | |||
217 | check( | ||
218 | r"use super::$0", | ||
219 | expect![[r#" | ||
220 | kw self | ||
221 | kw super:: | ||
222 | "#]], | ||
223 | ); | ||
224 | |||
225 | check( | ||
226 | r"use a::{b, $0}", | ||
227 | expect![[r#" | ||
228 | kw self | ||
229 | "#]], | ||
230 | ); | ||
231 | } | ||
232 | |||
233 | #[test] | ||
234 | fn test_keywords_at_source_file_level() { | ||
235 | check( | ||
236 | r"m$0", | ||
237 | expect![[r#" | ||
238 | kw pub(crate) | ||
239 | kw pub | ||
240 | kw unsafe | ||
241 | kw fn | ||
242 | kw const | ||
243 | kw type | ||
244 | kw use | ||
245 | kw impl | ||
246 | kw trait | ||
247 | kw static | ||
248 | kw extern | ||
249 | kw mod | ||
250 | kw enum | ||
251 | kw struct | ||
252 | kw union | ||
253 | "#]], | ||
254 | ); | ||
255 | } | ||
256 | |||
257 | #[test] | ||
258 | fn test_keywords_in_function() { | 223 | fn test_keywords_in_function() { |
259 | check( | 224 | check( |
260 | r"fn quux() { $0 }", | 225 | r"fn quux() { $0 }", |
@@ -263,11 +228,11 @@ mod tests { | |||
263 | kw fn | 228 | kw fn |
264 | kw const | 229 | kw const |
265 | kw type | 230 | kw type |
266 | kw use | ||
267 | kw impl | 231 | kw impl |
232 | kw extern | ||
233 | kw use | ||
268 | kw trait | 234 | kw trait |
269 | kw static | 235 | kw static |
270 | kw extern | ||
271 | kw mod | 236 | kw mod |
272 | kw match | 237 | kw match |
273 | kw while | 238 | kw while |
@@ -291,11 +256,11 @@ mod tests { | |||
291 | kw fn | 256 | kw fn |
292 | kw const | 257 | kw const |
293 | kw type | 258 | kw type |
294 | kw use | ||
295 | kw impl | 259 | kw impl |
260 | kw extern | ||
261 | kw use | ||
296 | kw trait | 262 | kw trait |
297 | kw static | 263 | kw static |
298 | kw extern | ||
299 | kw mod | 264 | kw mod |
300 | kw match | 265 | kw match |
301 | kw while | 266 | kw while |
@@ -319,11 +284,11 @@ mod tests { | |||
319 | kw fn | 284 | kw fn |
320 | kw const | 285 | kw const |
321 | kw type | 286 | kw type |
322 | kw use | ||
323 | kw impl | 287 | kw impl |
288 | kw extern | ||
289 | kw use | ||
324 | kw trait | 290 | kw trait |
325 | kw static | 291 | kw static |
326 | kw extern | ||
327 | kw mod | 292 | kw mod |
328 | kw match | 293 | kw match |
329 | kw while | 294 | kw while |
@@ -370,49 +335,6 @@ fn quux() -> i32 { | |||
370 | } | 335 | } |
371 | 336 | ||
372 | #[test] | 337 | #[test] |
373 | fn test_keywords_in_trait_def() { | ||
374 | check( | ||
375 | r"trait My { $0 }", | ||
376 | expect![[r#" | ||
377 | kw unsafe | ||
378 | kw fn | ||
379 | kw const | ||
380 | kw type | ||
381 | "#]], | ||
382 | ); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
386 | fn test_keywords_in_impl_def() { | ||
387 | check( | ||
388 | r"impl My { $0 }", | ||
389 | expect![[r#" | ||
390 | kw pub(crate) | ||
391 | kw pub | ||
392 | kw unsafe | ||
393 | kw fn | ||
394 | kw const | ||
395 | kw type | ||
396 | "#]], | ||
397 | ); | ||
398 | } | ||
399 | |||
400 | #[test] | ||
401 | fn test_keywords_in_impl_def_with_attr() { | ||
402 | check( | ||
403 | r"impl My { #[foo] $0 }", | ||
404 | expect![[r#" | ||
405 | kw pub(crate) | ||
406 | kw pub | ||
407 | kw unsafe | ||
408 | kw fn | ||
409 | kw const | ||
410 | kw type | ||
411 | "#]], | ||
412 | ); | ||
413 | } | ||
414 | |||
415 | #[test] | ||
416 | fn test_keywords_in_loop() { | 338 | fn test_keywords_in_loop() { |
417 | check( | 339 | check( |
418 | r"fn my() { loop { $0 } }", | 340 | r"fn my() { loop { $0 } }", |
@@ -421,11 +343,11 @@ fn quux() -> i32 { | |||
421 | kw fn | 343 | kw fn |
422 | kw const | 344 | kw const |
423 | kw type | 345 | kw type |
424 | kw use | ||
425 | kw impl | 346 | kw impl |
347 | kw extern | ||
348 | kw use | ||
426 | kw trait | 349 | kw trait |
427 | kw static | 350 | kw static |
428 | kw extern | ||
429 | kw mod | 351 | kw mod |
430 | kw match | 352 | kw match |
431 | kw while | 353 | kw while |
@@ -443,18 +365,6 @@ fn quux() -> i32 { | |||
443 | } | 365 | } |
444 | 366 | ||
445 | #[test] | 367 | #[test] |
446 | fn test_keywords_after_unsafe_in_item_list() { | ||
447 | check( | ||
448 | r"unsafe $0", | ||
449 | expect![[r#" | ||
450 | kw fn | ||
451 | kw trait | ||
452 | kw impl | ||
453 | "#]], | ||
454 | ); | ||
455 | } | ||
456 | |||
457 | #[test] | ||
458 | fn test_keywords_after_unsafe_in_block_expr() { | 368 | fn test_keywords_after_unsafe_in_block_expr() { |
459 | check( | 369 | check( |
460 | r"fn my_fn() { unsafe $0 }", | 370 | r"fn my_fn() { unsafe $0 }", |
@@ -467,44 +377,6 @@ fn quux() -> i32 { | |||
467 | } | 377 | } |
468 | 378 | ||
469 | #[test] | 379 | #[test] |
470 | fn test_mut_in_ref_and_in_fn_parameters_list() { | ||
471 | check( | ||
472 | r"fn my_fn(&$0) {}", | ||
473 | expect![[r#" | ||
474 | kw mut | ||
475 | "#]], | ||
476 | ); | ||
477 | check( | ||
478 | r"fn my_fn($0) {}", | ||
479 | expect![[r#" | ||
480 | kw mut | ||
481 | "#]], | ||
482 | ); | ||
483 | check( | ||
484 | r"fn my_fn() { let &$0 }", | ||
485 | expect![[r#" | ||
486 | kw mut | ||
487 | "#]], | ||
488 | ); | ||
489 | } | ||
490 | |||
491 | #[test] | ||
492 | fn test_where_keyword() { | ||
493 | check( | ||
494 | r"trait A $0", | ||
495 | expect![[r#" | ||
496 | kw where | ||
497 | "#]], | ||
498 | ); | ||
499 | check( | ||
500 | r"impl A $0", | ||
501 | expect![[r#" | ||
502 | kw where | ||
503 | "#]], | ||
504 | ); | ||
505 | } | ||
506 | |||
507 | #[test] | ||
508 | fn no_keyword_completion_in_comments() { | 380 | fn no_keyword_completion_in_comments() { |
509 | cov_mark::check!(no_keyword_completion_in_comments); | 381 | cov_mark::check!(no_keyword_completion_in_comments); |
510 | check( | 382 | check( |
@@ -536,17 +408,11 @@ Some multi-line comment$0 | |||
536 | fn test_completion_await_impls_future() { | 408 | fn test_completion_await_impls_future() { |
537 | check( | 409 | check( |
538 | r#" | 410 | r#" |
539 | //- /main.rs crate:main deps:std | 411 | //- minicore: future |
540 | use std::future::*; | 412 | use core::future::*; |
541 | struct A {} | 413 | struct A {} |
542 | impl Future for A {} | 414 | impl Future for A {} |
543 | fn foo(a: A) { a.$0 } | 415 | fn foo(a: A) { a.$0 } |
544 | |||
545 | //- /std/lib.rs crate:std | ||
546 | pub mod future { | ||
547 | #[lang = "future_trait"] | ||
548 | pub trait Future {} | ||
549 | } | ||
550 | "#, | 416 | "#, |
551 | expect![[r#" | 417 | expect![[r#" |
552 | kw await expr.await | 418 | kw await expr.await |
@@ -555,20 +421,12 @@ pub mod future { | |||
555 | 421 | ||
556 | check( | 422 | check( |
557 | r#" | 423 | r#" |
558 | //- /main.rs crate:main deps:std | 424 | //- minicore: future |
559 | use std::future::*; | 425 | use std::future::*; |
560 | fn foo() { | 426 | fn foo() { |
561 | let a = async {}; | 427 | let a = async {}; |
562 | a.$0 | 428 | a.$0 |
563 | } | 429 | } |
564 | |||
565 | //- /std/lib.rs crate:std | ||
566 | pub mod future { | ||
567 | #[lang = "future_trait"] | ||
568 | pub trait Future { | ||
569 | type Output; | ||
570 | } | ||
571 | } | ||
572 | "#, | 430 | "#, |
573 | expect![[r#" | 431 | expect![[r#" |
574 | kw await expr.await | 432 | kw await expr.await |
@@ -595,22 +453,6 @@ pub mod future { | |||
595 | } | 453 | } |
596 | 454 | ||
597 | #[test] | 455 | #[test] |
598 | fn before_field() { | ||
599 | check( | ||
600 | r#" | ||
601 | struct Foo { | ||
602 | $0 | ||
603 | pub f: i32, | ||
604 | } | ||
605 | "#, | ||
606 | expect![[r#" | ||
607 | kw pub(crate) | ||
608 | kw pub | ||
609 | "#]], | ||
610 | ) | ||
611 | } | ||
612 | |||
613 | #[test] | ||
614 | fn skip_struct_initializer() { | 456 | fn skip_struct_initializer() { |
615 | cov_mark::check!(no_keyword_completion_in_record_lit); | 457 | cov_mark::check!(no_keyword_completion_in_record_lit); |
616 | check( | 458 | check( |
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs index 8ccccb646..abf6935c9 100644 --- a/crates/ide_completion/src/completions/lifetime.rs +++ b/crates/ide_completion/src/completions/lifetime.rs | |||
@@ -49,18 +49,11 @@ pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) { | |||
49 | mod tests { | 49 | mod tests { |
50 | use expect_test::{expect, Expect}; | 50 | use expect_test::{expect, Expect}; |
51 | 51 | ||
52 | use crate::{ | 52 | use crate::tests::{check_edit, completion_list}; |
53 | test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, | ||
54 | CompletionConfig, CompletionKind, | ||
55 | }; | ||
56 | 53 | ||
57 | fn check(ra_fixture: &str, expect: Expect) { | 54 | fn check(ra_fixture: &str, expect: Expect) { |
58 | check_with_config(TEST_CONFIG, ra_fixture, expect); | 55 | let actual = completion_list(ra_fixture); |
59 | } | 56 | expect.assert_eq(&actual); |
60 | |||
61 | fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { | ||
62 | let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference); | ||
63 | expect.assert_eq(&actual) | ||
64 | } | 57 | } |
65 | 58 | ||
66 | #[test] | 59 | #[test] |
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs index 6a5746fb9..1c864c0e7 100644 --- a/crates/ide_completion/src/completions/mod_.rs +++ b/crates/ide_completion/src/completions/mod_.rs | |||
@@ -141,11 +141,11 @@ fn module_chain_to_containing_module_file( | |||
141 | 141 | ||
142 | #[cfg(test)] | 142 | #[cfg(test)] |
143 | mod tests { | 143 | mod tests { |
144 | use crate::{test_utils::completion_list, CompletionKind}; | 144 | use crate::tests::completion_list; |
145 | use expect_test::{expect, Expect}; | 145 | use expect_test::{expect, Expect}; |
146 | 146 | ||
147 | fn check(ra_fixture: &str, expect: Expect) { | 147 | fn check(ra_fixture: &str, expect: Expect) { |
148 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | 148 | let actual = completion_list(ra_fixture); |
149 | expect.assert_eq(&actual); | 149 | expect.assert_eq(&actual); |
150 | } | 150 | } |
151 | 151 | ||
@@ -153,17 +153,17 @@ mod tests { | |||
153 | fn lib_module_completion() { | 153 | fn lib_module_completion() { |
154 | check( | 154 | check( |
155 | r#" | 155 | r#" |
156 | //- /lib.rs | 156 | //- /lib.rs |
157 | mod $0 | 157 | mod $0 |
158 | //- /foo.rs | 158 | //- /foo.rs |
159 | fn foo() {} | 159 | fn foo() {} |
160 | //- /foo/ignored_foo.rs | 160 | //- /foo/ignored_foo.rs |
161 | fn ignored_foo() {} | 161 | fn ignored_foo() {} |
162 | //- /bar/mod.rs | 162 | //- /bar/mod.rs |
163 | fn bar() {} | 163 | fn bar() {} |
164 | //- /bar/ignored_bar.rs | 164 | //- /bar/ignored_bar.rs |
165 | fn ignored_bar() {} | 165 | fn ignored_bar() {} |
166 | "#, | 166 | "#, |
167 | expect![[r#" | 167 | expect![[r#" |
168 | md foo; | 168 | md foo; |
169 | md bar; | 169 | md bar; |
@@ -175,13 +175,13 @@ mod tests { | |||
175 | fn no_module_completion_with_module_body() { | 175 | fn no_module_completion_with_module_body() { |
176 | check( | 176 | check( |
177 | r#" | 177 | r#" |
178 | //- /lib.rs | 178 | //- /lib.rs |
179 | mod $0 { | 179 | mod $0 { |
180 | 180 | ||
181 | } | 181 | } |
182 | //- /foo.rs | 182 | //- /foo.rs |
183 | fn foo() {} | 183 | fn foo() {} |
184 | "#, | 184 | "#, |
185 | expect![[r#""#]], | 185 | expect![[r#""#]], |
186 | ); | 186 | ); |
187 | } | 187 | } |
@@ -190,17 +190,17 @@ mod tests { | |||
190 | fn main_module_completion() { | 190 | fn main_module_completion() { |
191 | check( | 191 | check( |
192 | r#" | 192 | r#" |
193 | //- /main.rs | 193 | //- /main.rs |
194 | mod $0 | 194 | mod $0 |
195 | //- /foo.rs | 195 | //- /foo.rs |
196 | fn foo() {} | 196 | fn foo() {} |
197 | //- /foo/ignored_foo.rs | 197 | //- /foo/ignored_foo.rs |
198 | fn ignored_foo() {} | 198 | fn ignored_foo() {} |
199 | //- /bar/mod.rs | 199 | //- /bar/mod.rs |
200 | fn bar() {} | 200 | fn bar() {} |
201 | //- /bar/ignored_bar.rs | 201 | //- /bar/ignored_bar.rs |
202 | fn ignored_bar() {} | 202 | fn ignored_bar() {} |
203 | "#, | 203 | "#, |
204 | expect![[r#" | 204 | expect![[r#" |
205 | md foo; | 205 | md foo; |
206 | md bar; | 206 | md bar; |
@@ -212,13 +212,13 @@ mod tests { | |||
212 | fn main_test_module_completion() { | 212 | fn main_test_module_completion() { |
213 | check( | 213 | check( |
214 | r#" | 214 | r#" |
215 | //- /main.rs | 215 | //- /main.rs |
216 | mod tests { | 216 | mod tests { |
217 | mod $0; | 217 | mod $0; |
218 | } | 218 | } |
219 | //- /tests/foo.rs | 219 | //- /tests/foo.rs |
220 | fn foo() {} | 220 | fn foo() {} |
221 | "#, | 221 | "#, |
222 | expect![[r#" | 222 | expect![[r#" |
223 | md foo | 223 | md foo |
224 | "#]], | 224 | "#]], |
@@ -229,19 +229,19 @@ mod tests { | |||
229 | fn directly_nested_module_completion() { | 229 | fn directly_nested_module_completion() { |
230 | check( | 230 | check( |
231 | r#" | 231 | r#" |
232 | //- /lib.rs | 232 | //- /lib.rs |
233 | mod foo; | 233 | mod foo; |
234 | //- /foo.rs | 234 | //- /foo.rs |
235 | mod $0; | 235 | mod $0; |
236 | //- /foo/bar.rs | 236 | //- /foo/bar.rs |
237 | fn bar() {} | 237 | fn bar() {} |
238 | //- /foo/bar/ignored_bar.rs | 238 | //- /foo/bar/ignored_bar.rs |
239 | fn ignored_bar() {} | 239 | fn ignored_bar() {} |
240 | //- /foo/baz/mod.rs | 240 | //- /foo/baz/mod.rs |
241 | fn baz() {} | 241 | fn baz() {} |
242 | //- /foo/moar/ignored_moar.rs | 242 | //- /foo/moar/ignored_moar.rs |
243 | fn ignored_moar() {} | 243 | fn ignored_moar() {} |
244 | "#, | 244 | "#, |
245 | expect![[r#" | 245 | expect![[r#" |
246 | md bar | 246 | md bar |
247 | md baz | 247 | md baz |
@@ -253,15 +253,15 @@ mod tests { | |||
253 | fn nested_in_source_module_completion() { | 253 | fn nested_in_source_module_completion() { |
254 | check( | 254 | check( |
255 | r#" | 255 | r#" |
256 | //- /lib.rs | 256 | //- /lib.rs |
257 | mod foo; | 257 | mod foo; |
258 | //- /foo.rs | 258 | //- /foo.rs |
259 | mod bar { | 259 | mod bar { |
260 | mod $0 | 260 | mod $0 |
261 | } | 261 | } |
262 | //- /foo/bar/baz.rs | 262 | //- /foo/bar/baz.rs |
263 | fn baz() {} | 263 | fn baz() {} |
264 | "#, | 264 | "#, |
265 | expect![[r#" | 265 | expect![[r#" |
266 | md baz; | 266 | md baz; |
267 | "#]], | 267 | "#]], |
@@ -299,16 +299,16 @@ mod tests { | |||
299 | fn already_declared_bin_module_completion_omitted() { | 299 | fn already_declared_bin_module_completion_omitted() { |
300 | check( | 300 | check( |
301 | r#" | 301 | r#" |
302 | //- /src/bin.rs crate:main | 302 | //- /src/bin.rs crate:main |
303 | fn main() {} | 303 | fn main() {} |
304 | //- /src/bin/foo.rs | 304 | //- /src/bin/foo.rs |
305 | mod $0 | 305 | mod $0 |
306 | //- /src/bin/bar.rs | 306 | //- /src/bin/bar.rs |
307 | mod foo; | 307 | mod foo; |
308 | fn bar() {} | 308 | fn bar() {} |
309 | //- /src/bin/bar/bar_ignored.rs | 309 | //- /src/bin/bar/bar_ignored.rs |
310 | fn bar_ignored() {} | 310 | fn bar_ignored() {} |
311 | "#, | 311 | "#, |
312 | expect![[r#""#]], | 312 | expect![[r#""#]], |
313 | ); | 313 | ); |
314 | } | 314 | } |
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 1daa8595a..bd13a62d7 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -13,7 +13,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
13 | if let Some(hir::Adt::Enum(e)) = | 13 | if let Some(hir::Adt::Enum(e)) = |
14 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) | 14 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
15 | { | 15 | { |
16 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { | 16 | super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { |
17 | acc.add_qualified_variant_pat(ctx, variant, path.clone()); | 17 | acc.add_qualified_variant_pat(ctx, variant, path.clone()); |
18 | acc.add_qualified_enum_variant(ctx, variant, path); | 18 | acc.add_qualified_enum_variant(ctx, variant, path); |
19 | }); | 19 | }); |
@@ -55,398 +55,3 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
55 | } | 55 | } |
56 | }); | 56 | }); |
57 | } | 57 | } |
58 | |||
59 | #[cfg(test)] | ||
60 | mod tests { | ||
61 | use expect_test::{expect, Expect}; | ||
62 | |||
63 | use crate::{ | ||
64 | test_utils::{check_edit, completion_list}, | ||
65 | CompletionKind, | ||
66 | }; | ||
67 | |||
68 | fn check(ra_fixture: &str, expect: Expect) { | ||
69 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | ||
70 | expect.assert_eq(&actual) | ||
71 | } | ||
72 | |||
73 | fn check_snippet(ra_fixture: &str, expect: Expect) { | ||
74 | let actual = completion_list(ra_fixture, CompletionKind::Snippet); | ||
75 | expect.assert_eq(&actual) | ||
76 | } | ||
77 | |||
78 | #[test] | ||
79 | fn completes_enum_variants_and_modules() { | ||
80 | check( | ||
81 | r#" | ||
82 | enum E { X } | ||
83 | use self::E::X; | ||
84 | const Z: E = E::X; | ||
85 | mod m {} | ||
86 | |||
87 | static FOO: E = E::X; | ||
88 | struct Bar { f: u32 } | ||
89 | |||
90 | fn foo() { | ||
91 | match E::X { a$0 } | ||
92 | } | ||
93 | "#, | ||
94 | expect![[r#" | ||
95 | en E | ||
96 | ct Z | ||
97 | st Bar | ||
98 | ev X | ||
99 | md m | ||
100 | "#]], | ||
101 | ); | ||
102 | } | ||
103 | |||
104 | #[test] | ||
105 | fn does_not_complete_non_fn_macros() { | ||
106 | check( | ||
107 | r#" | ||
108 | macro_rules! m { ($e:expr) => { $e } } | ||
109 | enum E { X } | ||
110 | |||
111 | #[rustc_builtin_macro] | ||
112 | macro Clone {} | ||
113 | |||
114 | fn foo() { | ||
115 | match E::X { $0 } | ||
116 | } | ||
117 | "#, | ||
118 | expect![[r#" | ||
119 | ev E::X () | ||
120 | en E | ||
121 | ma m!(…) macro_rules! m | ||
122 | "#]], | ||
123 | ); | ||
124 | } | ||
125 | |||
126 | #[test] | ||
127 | fn completes_in_simple_macro_call() { | ||
128 | check( | ||
129 | r#" | ||
130 | macro_rules! m { ($e:expr) => { $e } } | ||
131 | enum E { X } | ||
132 | |||
133 | fn foo() { | ||
134 | m!(match E::X { a$0 }) | ||
135 | } | ||
136 | "#, | ||
137 | expect![[r#" | ||
138 | ev E::X () | ||
139 | en E | ||
140 | ma m!(…) macro_rules! m | ||
141 | "#]], | ||
142 | ); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn completes_in_irrefutable_let() { | ||
147 | check( | ||
148 | r#" | ||
149 | enum E { X } | ||
150 | use self::E::X; | ||
151 | const Z: E = E::X; | ||
152 | mod m {} | ||
153 | |||
154 | static FOO: E = E::X; | ||
155 | struct Bar { f: u32 } | ||
156 | |||
157 | fn foo() { | ||
158 | let a$0 | ||
159 | } | ||
160 | "#, | ||
161 | expect![[r#" | ||
162 | st Bar | ||
163 | "#]], | ||
164 | ); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
168 | fn completes_in_param() { | ||
169 | check( | ||
170 | r#" | ||
171 | enum E { X } | ||
172 | |||
173 | static FOO: E = E::X; | ||
174 | struct Bar { f: u32 } | ||
175 | |||
176 | fn foo(a$0) { | ||
177 | } | ||
178 | "#, | ||
179 | expect![[r#" | ||
180 | st Bar | ||
181 | "#]], | ||
182 | ); | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn completes_pat_in_let() { | ||
187 | check_snippet( | ||
188 | r#" | ||
189 | struct Bar { f: u32 } | ||
190 | |||
191 | fn foo() { | ||
192 | let a$0 | ||
193 | } | ||
194 | "#, | ||
195 | expect![[r#" | ||
196 | bn Bar Bar { f$1 }$0 | ||
197 | "#]], | ||
198 | ); | ||
199 | } | ||
200 | |||
201 | #[test] | ||
202 | fn completes_param_pattern() { | ||
203 | check_snippet( | ||
204 | r#" | ||
205 | struct Foo { bar: String, baz: String } | ||
206 | struct Bar(String, String); | ||
207 | struct Baz; | ||
208 | fn outer(a$0) {} | ||
209 | "#, | ||
210 | expect![[r#" | ||
211 | bn Foo Foo { bar$1, baz$2 }: Foo$0 | ||
212 | bn Bar Bar($1, $2): Bar$0 | ||
213 | "#]], | ||
214 | ) | ||
215 | } | ||
216 | |||
217 | #[test] | ||
218 | fn completes_let_pattern() { | ||
219 | check_snippet( | ||
220 | r#" | ||
221 | struct Foo { bar: String, baz: String } | ||
222 | struct Bar(String, String); | ||
223 | struct Baz; | ||
224 | fn outer() { | ||
225 | let a$0 | ||
226 | } | ||
227 | "#, | ||
228 | expect![[r#" | ||
229 | bn Foo Foo { bar$1, baz$2 }$0 | ||
230 | bn Bar Bar($1, $2)$0 | ||
231 | "#]], | ||
232 | ) | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn completes_refutable_pattern() { | ||
237 | check_snippet( | ||
238 | r#" | ||
239 | struct Foo { bar: i32, baz: i32 } | ||
240 | struct Bar(String, String); | ||
241 | struct Baz; | ||
242 | fn outer() { | ||
243 | match () { | ||
244 | a$0 | ||
245 | } | ||
246 | } | ||
247 | "#, | ||
248 | expect![[r#" | ||
249 | bn Foo Foo { bar$1, baz$2 }$0 | ||
250 | bn Bar Bar($1, $2)$0 | ||
251 | "#]], | ||
252 | ) | ||
253 | } | ||
254 | |||
255 | #[test] | ||
256 | fn omits_private_fields_pat() { | ||
257 | check_snippet( | ||
258 | r#" | ||
259 | mod foo { | ||
260 | pub struct Foo { pub bar: i32, baz: i32 } | ||
261 | pub struct Bar(pub String, String); | ||
262 | pub struct Invisible(String, String); | ||
263 | } | ||
264 | use foo::*; | ||
265 | |||
266 | fn outer() { | ||
267 | match () { | ||
268 | a$0 | ||
269 | } | ||
270 | } | ||
271 | "#, | ||
272 | expect![[r#" | ||
273 | bn Foo Foo { bar$1, .. }$0 | ||
274 | bn Bar Bar($1, ..)$0 | ||
275 | "#]], | ||
276 | ) | ||
277 | } | ||
278 | |||
279 | #[test] | ||
280 | fn only_shows_ident_completion() { | ||
281 | check_edit( | ||
282 | "Foo", | ||
283 | r#" | ||
284 | struct Foo(i32); | ||
285 | fn main() { | ||
286 | match Foo(92) { | ||
287 | a$0(92) => (), | ||
288 | } | ||
289 | } | ||
290 | "#, | ||
291 | r#" | ||
292 | struct Foo(i32); | ||
293 | fn main() { | ||
294 | match Foo(92) { | ||
295 | Foo(92) => (), | ||
296 | } | ||
297 | } | ||
298 | "#, | ||
299 | ); | ||
300 | } | ||
301 | |||
302 | #[test] | ||
303 | fn completes_self_pats() { | ||
304 | check_snippet( | ||
305 | r#" | ||
306 | struct Foo(i32); | ||
307 | impl Foo { | ||
308 | fn foo() { | ||
309 | match () { | ||
310 | a$0 | ||
311 | } | ||
312 | } | ||
313 | } | ||
314 | "#, | ||
315 | expect![[r#" | ||
316 | bn Self Self($1)$0 | ||
317 | bn Foo Foo($1)$0 | ||
318 | "#]], | ||
319 | ) | ||
320 | } | ||
321 | |||
322 | #[test] | ||
323 | fn completes_qualified_variant() { | ||
324 | check_snippet( | ||
325 | r#" | ||
326 | enum Foo { | ||
327 | Bar { baz: i32 } | ||
328 | } | ||
329 | impl Foo { | ||
330 | fn foo() { | ||
331 | match {Foo::Bar { baz: 0 }} { | ||
332 | B$0 | ||
333 | } | ||
334 | } | ||
335 | } | ||
336 | "#, | ||
337 | expect![[r#" | ||
338 | bn Self::Bar Self::Bar { baz$1 }$0 | ||
339 | bn Foo::Bar Foo::Bar { baz$1 }$0 | ||
340 | "#]], | ||
341 | ) | ||
342 | } | ||
343 | |||
344 | #[test] | ||
345 | fn completes_enum_variant_matcharm() { | ||
346 | check( | ||
347 | r#" | ||
348 | enum Foo { Bar, Baz, Quux } | ||
349 | |||
350 | fn main() { | ||
351 | let foo = Foo::Quux; | ||
352 | match foo { Qu$0 } | ||
353 | } | ||
354 | "#, | ||
355 | expect![[r#" | ||
356 | ev Foo::Bar () | ||
357 | ev Foo::Baz () | ||
358 | ev Foo::Quux () | ||
359 | en Foo | ||
360 | "#]], | ||
361 | ) | ||
362 | } | ||
363 | |||
364 | #[test] | ||
365 | fn completes_enum_variant_matcharm_ref() { | ||
366 | check( | ||
367 | r#" | ||
368 | enum Foo { Bar, Baz, Quux } | ||
369 | |||
370 | fn main() { | ||
371 | let foo = Foo::Quux; | ||
372 | match &foo { Qu$0 } | ||
373 | } | ||
374 | "#, | ||
375 | expect![[r#" | ||
376 | ev Foo::Bar () | ||
377 | ev Foo::Baz () | ||
378 | ev Foo::Quux () | ||
379 | en Foo | ||
380 | "#]], | ||
381 | ) | ||
382 | } | ||
383 | |||
384 | #[test] | ||
385 | fn completes_enum_variant_iflet() { | ||
386 | check( | ||
387 | r#" | ||
388 | enum Foo { Bar, Baz, Quux } | ||
389 | |||
390 | fn main() { | ||
391 | let foo = Foo::Quux; | ||
392 | if let Qu$0 = foo { } | ||
393 | } | ||
394 | "#, | ||
395 | expect![[r#" | ||
396 | ev Foo::Bar () | ||
397 | ev Foo::Baz () | ||
398 | ev Foo::Quux () | ||
399 | en Foo | ||
400 | "#]], | ||
401 | ) | ||
402 | } | ||
403 | |||
404 | #[test] | ||
405 | fn completes_enum_variant_impl() { | ||
406 | check( | ||
407 | r#" | ||
408 | enum Foo { Bar, Baz, Quux } | ||
409 | impl Foo { | ||
410 | fn foo() { match Foo::Bar { Q$0 } } | ||
411 | } | ||
412 | "#, | ||
413 | expect![[r#" | ||
414 | ev Self::Bar () | ||
415 | ev Self::Baz () | ||
416 | ev Self::Quux () | ||
417 | ev Foo::Bar () | ||
418 | ev Foo::Baz () | ||
419 | ev Foo::Quux () | ||
420 | sp Self | ||
421 | en Foo | ||
422 | "#]], | ||
423 | ) | ||
424 | } | ||
425 | |||
426 | #[test] | ||
427 | fn completes_in_record_field_pat() { | ||
428 | check_snippet( | ||
429 | r#" | ||
430 | struct Foo { bar: Bar } | ||
431 | struct Bar(u32); | ||
432 | fn outer(Foo { bar: $0 }: Foo) {} | ||
433 | "#, | ||
434 | expect![[r#" | ||
435 | bn Foo Foo { bar$1 }$0 | ||
436 | bn Bar Bar($1)$0 | ||
437 | "#]], | ||
438 | ) | ||
439 | } | ||
440 | |||
441 | #[test] | ||
442 | fn skips_in_record_field_pat_name() { | ||
443 | check_snippet( | ||
444 | r#" | ||
445 | struct Foo { bar: Bar } | ||
446 | struct Bar(u32); | ||
447 | fn outer(Foo { bar$0 }: Foo) {} | ||
448 | "#, | ||
449 | expect![[r#""#]], | ||
450 | ) | ||
451 | } | ||
452 | } | ||
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 9f98b21be..4e20ec003 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -307,12 +307,12 @@ mod tests { | |||
307 | use expect_test::{expect, Expect}; | 307 | use expect_test::{expect, Expect}; |
308 | 308 | ||
309 | use crate::{ | 309 | use crate::{ |
310 | test_utils::{check_edit, completion_list}, | 310 | tests::{check_edit, filtered_completion_list}, |
311 | CompletionKind, | 311 | CompletionKind, |
312 | }; | 312 | }; |
313 | 313 | ||
314 | fn check(ra_fixture: &str, expect: Expect) { | 314 | fn check(ra_fixture: &str, expect: Expect) { |
315 | let actual = completion_list(ra_fixture, CompletionKind::Postfix); | 315 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Postfix); |
316 | expect.assert_eq(&actual) | 316 | expect.assert_eq(&actual) |
317 | } | 317 | } |
318 | 318 | ||
@@ -436,18 +436,15 @@ fn main() { | |||
436 | check_edit( | 436 | check_edit( |
437 | "ifl", | 437 | "ifl", |
438 | r#" | 438 | r#" |
439 | enum Option<T> { Some(T), None } | 439 | //- minicore: option |
440 | |||
441 | fn main() { | 440 | fn main() { |
442 | let bar = Option::Some(true); | 441 | let bar = Some(true); |
443 | bar.$0 | 442 | bar.$0 |
444 | } | 443 | } |
445 | "#, | 444 | "#, |
446 | r#" | 445 | r#" |
447 | enum Option<T> { Some(T), None } | ||
448 | |||
449 | fn main() { | 446 | fn main() { |
450 | let bar = Option::Some(true); | 447 | let bar = Some(true); |
451 | if let Some($1) = bar { | 448 | if let Some($1) = bar { |
452 | $0 | 449 | $0 |
453 | } | 450 | } |
@@ -461,18 +458,15 @@ fn main() { | |||
461 | check_edit( | 458 | check_edit( |
462 | "match", | 459 | "match", |
463 | r#" | 460 | r#" |
464 | enum Result<T, E> { Ok(T), Err(E) } | 461 | //- minicore: result |
465 | |||
466 | fn main() { | 462 | fn main() { |
467 | let bar = Result::Ok(true); | 463 | let bar = Ok(true); |
468 | bar.$0 | 464 | bar.$0 |
469 | } | 465 | } |
470 | "#, | 466 | "#, |
471 | r#" | 467 | r#" |
472 | enum Result<T, E> { Ok(T), Err(E) } | ||
473 | |||
474 | fn main() { | 468 | fn main() { |
475 | let bar = Result::Ok(true); | 469 | let bar = Ok(true); |
476 | match bar { | 470 | match bar { |
477 | Ok(${1:_}) => {$2}, | 471 | Ok(${1:_}) => {$2}, |
478 | Err(${3:_}) => {$0}, | 472 | Err(${3:_}) => {$0}, |
@@ -515,18 +509,15 @@ fn main() { | |||
515 | check_edit( | 509 | check_edit( |
516 | "ifl", | 510 | "ifl", |
517 | r#" | 511 | r#" |
518 | enum Option<T> { Some(T), None } | 512 | //- minicore: option |
519 | |||
520 | fn main() { | 513 | fn main() { |
521 | let bar = &Option::Some(true); | 514 | let bar = &Some(true); |
522 | bar.$0 | 515 | bar.$0 |
523 | } | 516 | } |
524 | "#, | 517 | "#, |
525 | r#" | 518 | r#" |
526 | enum Option<T> { Some(T), None } | ||
527 | |||
528 | fn main() { | 519 | fn main() { |
529 | let bar = &Option::Some(true); | 520 | let bar = &Some(true); |
530 | if let Some($1) = bar { | 521 | if let Some($1) = bar { |
531 | $0 | 522 | $0 |
532 | } | 523 | } |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 6083537b7..1b8997ecf 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -19,6 +19,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
19 | Some(res) => res, | 19 | Some(res) => res, |
20 | None => return, | 20 | None => return, |
21 | }; | 21 | }; |
22 | |||
22 | let context_module = ctx.scope.module(); | 23 | let context_module = ctx.scope.module(); |
23 | 24 | ||
24 | if ctx.expects_item() || ctx.expects_assoc_item() { | 25 | if ctx.expects_item() || ctx.expects_assoc_item() { |
@@ -48,7 +49,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
48 | hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { | 49 | hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { |
49 | let module_scope = module.scope(ctx.db, context_module); | 50 | let module_scope = module.scope(ctx.db, context_module); |
50 | for (name, def) in module_scope { | 51 | for (name, def) in module_scope { |
51 | if ctx.use_item_syntax.is_some() { | 52 | if ctx.in_use_tree() { |
52 | if let hir::ScopeDef::Unknown = def { | 53 | if let hir::ScopeDef::Unknown = def { |
53 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { | 54 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { |
54 | if name_ref.syntax().text() == name.to_string().as_str() { | 55 | if name_ref.syntax().text() == name.to_string().as_str() { |
@@ -60,21 +61,37 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
60 | } | 61 | } |
61 | } | 62 | } |
62 | 63 | ||
63 | if let hir::ScopeDef::MacroDef(macro_def) = def { | 64 | let add_resolution = match def { |
64 | if !macro_def.is_fn_like() { | 65 | // Don't suggest attribute macros and derives. |
65 | // Don't suggest attribute macros and derives. | 66 | hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(), |
66 | continue; | 67 | // no values in type places |
68 | hir::ScopeDef::ModuleDef( | ||
69 | hir::ModuleDef::Function(_) | ||
70 | | hir::ModuleDef::Variant(_) | ||
71 | | hir::ModuleDef::Static(_), | ||
72 | ) | ||
73 | | hir::ScopeDef::Local(_) => !ctx.expects_type(), | ||
74 | // unless its a constant in a generic arg list position | ||
75 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => { | ||
76 | !ctx.expects_type() || ctx.expects_generic_arg() | ||
67 | } | 77 | } |
68 | } | 78 | _ => true, |
79 | }; | ||
69 | 80 | ||
70 | acc.add_resolution(ctx, name, &def); | 81 | if add_resolution { |
82 | acc.add_resolution(ctx, name, &def); | ||
83 | } | ||
71 | } | 84 | } |
72 | } | 85 | } |
73 | hir::PathResolution::Def(def @ hir::ModuleDef::Adt(_)) | 86 | hir::PathResolution::Def( |
74 | | hir::PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) | 87 | def |
75 | | hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => { | 88 | @ |
89 | (hir::ModuleDef::Adt(_) | ||
90 | | hir::ModuleDef::TypeAlias(_) | ||
91 | | hir::ModuleDef::BuiltinType(_)), | ||
92 | ) => { | ||
76 | if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def { | 93 | if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def { |
77 | add_enum_variants(ctx, acc, e); | 94 | add_enum_variants(acc, ctx, e); |
78 | } | 95 | } |
79 | let ty = match def { | 96 | let ty = match def { |
80 | hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), | 97 | hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), |
@@ -82,7 +99,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
82 | let ty = a.ty(ctx.db); | 99 | let ty = a.ty(ctx.db); |
83 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { | 100 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { |
84 | cov_mark::hit!(completes_variant_through_alias); | 101 | cov_mark::hit!(completes_variant_through_alias); |
85 | add_enum_variants(ctx, acc, e); | 102 | add_enum_variants(acc, ctx, e); |
86 | } | 103 | } |
87 | ty | 104 | ty |
88 | } | 105 | } |
@@ -107,11 +124,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
107 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 124 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
108 | return None; | 125 | return None; |
109 | } | 126 | } |
110 | match item { | 127 | add_assoc_item(acc, ctx, item); |
111 | hir::AssocItem::Function(func) => acc.add_function(ctx, func, None), | ||
112 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
113 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
114 | } | ||
115 | None::<()> | 128 | None::<()> |
116 | }); | 129 | }); |
117 | 130 | ||
@@ -133,11 +146,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
133 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 146 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
134 | continue; | 147 | continue; |
135 | } | 148 | } |
136 | match item { | 149 | add_assoc_item(acc, ctx, item); |
137 | hir::AssocItem::Function(func) => acc.add_function(ctx, func, None), | ||
138 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
139 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
140 | } | ||
141 | } | 150 | } |
142 | } | 151 | } |
143 | hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { | 152 | hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { |
@@ -149,7 +158,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
149 | }; | 158 | }; |
150 | 159 | ||
151 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { | 160 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { |
152 | add_enum_variants(ctx, acc, e); | 161 | add_enum_variants(acc, ctx, e); |
153 | } | 162 | } |
154 | 163 | ||
155 | let traits_in_scope = ctx.scope.traits_in_scope(); | 164 | let traits_in_scope = ctx.scope.traits_in_scope(); |
@@ -162,11 +171,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
162 | // We might iterate candidates of a trait multiple times here, so deduplicate | 171 | // We might iterate candidates of a trait multiple times here, so deduplicate |
163 | // them. | 172 | // them. |
164 | if seen.insert(item) { | 173 | if seen.insert(item) { |
165 | match item { | 174 | add_assoc_item(acc, ctx, item); |
166 | hir::AssocItem::Function(func) => acc.add_function(ctx, func, None), | ||
167 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
168 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
169 | } | ||
170 | } | 175 | } |
171 | None::<()> | 176 | None::<()> |
172 | }); | 177 | }); |
@@ -176,82 +181,44 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
176 | } | 181 | } |
177 | } | 182 | } |
178 | 183 | ||
179 | fn add_enum_variants(ctx: &CompletionContext, acc: &mut Completions, e: hir::Enum) { | 184 | fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) { |
180 | for variant in e.variants(ctx.db) { | 185 | match item { |
181 | acc.add_enum_variant(ctx, variant, None); | 186 | hir::AssocItem::Function(func) if !ctx.expects_type() => acc.add_function(ctx, func, None), |
187 | hir::AssocItem::Const(ct) if !ctx.expects_type() || ctx.expects_generic_arg() => { | ||
188 | acc.add_const(ctx, ct) | ||
189 | } | ||
190 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
191 | _ => (), | ||
182 | } | 192 | } |
183 | } | 193 | } |
184 | 194 | ||
195 | fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) { | ||
196 | if ctx.expects_type() { | ||
197 | return; | ||
198 | } | ||
199 | e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None)); | ||
200 | } | ||
201 | |||
185 | #[cfg(test)] | 202 | #[cfg(test)] |
186 | mod tests { | 203 | mod tests { |
187 | use expect_test::{expect, Expect}; | 204 | use expect_test::{expect, Expect}; |
188 | 205 | ||
189 | use crate::{ | 206 | use crate::{ |
190 | test_utils::{check_edit, completion_list}, | 207 | tests::{check_edit, filtered_completion_list}, |
191 | CompletionKind, | 208 | CompletionKind, |
192 | }; | 209 | }; |
193 | 210 | ||
194 | fn check(ra_fixture: &str, expect: Expect) { | 211 | fn check(ra_fixture: &str, expect: Expect) { |
195 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 212 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); |
196 | expect.assert_eq(&actual); | 213 | expect.assert_eq(&actual); |
197 | } | 214 | } |
198 | 215 | ||
199 | fn check_builtin(ra_fixture: &str, expect: Expect) { | 216 | fn check_builtin(ra_fixture: &str, expect: Expect) { |
200 | let actual = completion_list(ra_fixture, CompletionKind::BuiltinType); | 217 | let actual = filtered_completion_list(ra_fixture, CompletionKind::BuiltinType); |
201 | expect.assert_eq(&actual); | 218 | expect.assert_eq(&actual); |
202 | } | 219 | } |
203 | 220 | ||
204 | #[test] | 221 | #[test] |
205 | fn dont_complete_current_use() { | ||
206 | cov_mark::check!(dont_complete_current_use); | ||
207 | check(r#"use self::foo$0;"#, expect![[""]]); | ||
208 | } | ||
209 | |||
210 | #[test] | ||
211 | fn dont_complete_values_in_type_pos() { | ||
212 | check( | ||
213 | r#" | ||
214 | const FOO: () = (); | ||
215 | static BAR: () = (); | ||
216 | struct Baz; | ||
217 | fn foo() { | ||
218 | let _: self::$0; | ||
219 | } | ||
220 | "#, | ||
221 | expect![[r#" | ||
222 | st Baz | ||
223 | "#]], | ||
224 | ); | ||
225 | } | ||
226 | |||
227 | #[test] | ||
228 | fn dont_complete_enum_variants_in_type_pos() { | ||
229 | check( | ||
230 | r#" | ||
231 | enum Foo { Bar } | ||
232 | fn foo() { | ||
233 | let _: Foo::$0; | ||
234 | } | ||
235 | "#, | ||
236 | expect![[r#""#]], | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn dont_complete_current_use_in_braces_with_glob() { | ||
242 | check( | ||
243 | r#" | ||
244 | mod foo { pub struct S; } | ||
245 | use self::{foo::*, bar$0}; | ||
246 | "#, | ||
247 | expect![[r#" | ||
248 | st S | ||
249 | md foo | ||
250 | "#]], | ||
251 | ); | ||
252 | } | ||
253 | |||
254 | #[test] | ||
255 | fn dont_complete_primitive_in_use() { | 222 | fn dont_complete_primitive_in_use() { |
256 | check_builtin(r#"use self::$0;"#, expect![[""]]); | 223 | check_builtin(r#"use self::$0;"#, expect![[""]]); |
257 | } | 224 | } |
@@ -262,134 +229,6 @@ use self::{foo::*, bar$0}; | |||
262 | } | 229 | } |
263 | 230 | ||
264 | #[test] | 231 | #[test] |
265 | fn completes_primitives() { | ||
266 | check_builtin( | ||
267 | r#"fn main() { let _: $0 = 92; }"#, | ||
268 | expect![[r#" | ||
269 | bt u32 | ||
270 | bt bool | ||
271 | bt u8 | ||
272 | bt isize | ||
273 | bt u16 | ||
274 | bt u64 | ||
275 | bt u128 | ||
276 | bt f32 | ||
277 | bt i128 | ||
278 | bt i16 | ||
279 | bt str | ||
280 | bt i64 | ||
281 | bt char | ||
282 | bt f64 | ||
283 | bt i32 | ||
284 | bt i8 | ||
285 | bt usize | ||
286 | "#]], | ||
287 | ); | ||
288 | } | ||
289 | |||
290 | #[test] | ||
291 | fn completes_mod_with_same_name_as_function() { | ||
292 | check( | ||
293 | r#" | ||
294 | use self::my::$0; | ||
295 | |||
296 | mod my { pub struct Bar; } | ||
297 | fn my() {} | ||
298 | "#, | ||
299 | expect![[r#" | ||
300 | st Bar | ||
301 | "#]], | ||
302 | ); | ||
303 | } | ||
304 | |||
305 | #[test] | ||
306 | fn filters_visibility() { | ||
307 | check( | ||
308 | r#" | ||
309 | use self::my::$0; | ||
310 | |||
311 | mod my { | ||
312 | struct Bar; | ||
313 | pub struct Foo; | ||
314 | pub use Bar as PublicBar; | ||
315 | } | ||
316 | "#, | ||
317 | expect![[r#" | ||
318 | st Foo | ||
319 | st PublicBar | ||
320 | "#]], | ||
321 | ); | ||
322 | } | ||
323 | |||
324 | #[test] | ||
325 | fn completes_use_item_starting_with_self() { | ||
326 | check( | ||
327 | r#" | ||
328 | use self::m::$0; | ||
329 | |||
330 | mod m { pub struct Bar; } | ||
331 | "#, | ||
332 | expect![[r#" | ||
333 | st Bar | ||
334 | "#]], | ||
335 | ); | ||
336 | } | ||
337 | |||
338 | #[test] | ||
339 | fn completes_use_item_starting_with_crate() { | ||
340 | check( | ||
341 | r#" | ||
342 | //- /lib.rs | ||
343 | mod foo; | ||
344 | struct Spam; | ||
345 | //- /foo.rs | ||
346 | use crate::Sp$0 | ||
347 | "#, | ||
348 | expect![[r#" | ||
349 | md foo | ||
350 | st Spam | ||
351 | "#]], | ||
352 | ); | ||
353 | } | ||
354 | |||
355 | #[test] | ||
356 | fn completes_nested_use_tree() { | ||
357 | check( | ||
358 | r#" | ||
359 | //- /lib.rs | ||
360 | mod foo; | ||
361 | struct Spam; | ||
362 | //- /foo.rs | ||
363 | use crate::{Sp$0}; | ||
364 | "#, | ||
365 | expect![[r#" | ||
366 | md foo | ||
367 | st Spam | ||
368 | "#]], | ||
369 | ); | ||
370 | } | ||
371 | |||
372 | #[test] | ||
373 | fn completes_deeply_nested_use_tree() { | ||
374 | check( | ||
375 | r#" | ||
376 | //- /lib.rs | ||
377 | mod foo; | ||
378 | pub mod bar { | ||
379 | pub mod baz { | ||
380 | pub struct Spam; | ||
381 | } | ||
382 | } | ||
383 | //- /foo.rs | ||
384 | use crate::{bar::{baz::Sp$0}}; | ||
385 | "#, | ||
386 | expect![[r#" | ||
387 | st Spam | ||
388 | "#]], | ||
389 | ); | ||
390 | } | ||
391 | |||
392 | #[test] | ||
393 | fn completes_enum_variant() { | 232 | fn completes_enum_variant() { |
394 | check( | 233 | check( |
395 | r#" | 234 | r#" |
@@ -486,22 +325,6 @@ fn foo() { let _ = U::$0 } | |||
486 | } | 325 | } |
487 | 326 | ||
488 | #[test] | 327 | #[test] |
489 | fn completes_use_paths_across_crates() { | ||
490 | check( | ||
491 | r#" | ||
492 | //- /main.rs crate:main deps:foo | ||
493 | use foo::$0; | ||
494 | |||
495 | //- /foo/lib.rs crate:foo | ||
496 | pub mod bar { pub struct S; } | ||
497 | "#, | ||
498 | expect![[r#" | ||
499 | md bar | ||
500 | "#]], | ||
501 | ); | ||
502 | } | ||
503 | |||
504 | #[test] | ||
505 | fn completes_trait_associated_method_1() { | 328 | fn completes_trait_associated_method_1() { |
506 | check( | 329 | check( |
507 | r#" | 330 | r#" |
@@ -683,63 +506,6 @@ fn f() {m::$0} | |||
683 | } | 506 | } |
684 | 507 | ||
685 | #[test] | 508 | #[test] |
686 | fn completes_in_assoc_item_list() { | ||
687 | check( | ||
688 | r#" | ||
689 | #[macro_export] | ||
690 | macro_rules! foo { () => {} } | ||
691 | mod bar {} | ||
692 | |||
693 | struct MyStruct {} | ||
694 | impl MyStruct { | ||
695 | crate::$0 | ||
696 | } | ||
697 | "#, | ||
698 | expect![[r##" | ||
699 | md bar | ||
700 | ma foo!(…) #[macro_export] macro_rules! foo | ||
701 | "##]], | ||
702 | ); | ||
703 | } | ||
704 | |||
705 | #[test] | ||
706 | fn completes_in_item_list() { | ||
707 | check( | ||
708 | r#" | ||
709 | struct MyStruct {} | ||
710 | #[macro_export] | ||
711 | macro_rules! foo {} | ||
712 | mod bar {} | ||
713 | |||
714 | crate::$0 | ||
715 | "#, | ||
716 | expect![[r#" | ||
717 | md bar | ||
718 | ma foo!(…) #[macro_export] macro_rules! foo | ||
719 | "#]], | ||
720 | ) | ||
721 | } | ||
722 | |||
723 | #[test] | ||
724 | fn test_super_super_completion() { | ||
725 | check( | ||
726 | r#" | ||
727 | mod a { | ||
728 | const A: usize = 0; | ||
729 | mod b { | ||
730 | const B: usize = 0; | ||
731 | mod c { use super::super::$0 } | ||
732 | } | ||
733 | } | ||
734 | "#, | ||
735 | expect![[r#" | ||
736 | md b | ||
737 | ct A | ||
738 | "#]], | ||
739 | ); | ||
740 | } | ||
741 | |||
742 | #[test] | ||
743 | fn completes_reexported_items_under_correct_name() { | 509 | fn completes_reexported_items_under_correct_name() { |
744 | check( | 510 | check( |
745 | r#" | 511 | r#" |
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index 0ac47cdbe..e876337f1 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs | |||
@@ -48,44 +48,29 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> | |||
48 | #[cfg(test)] | 48 | #[cfg(test)] |
49 | mod tests { | 49 | mod tests { |
50 | use expect_test::{expect, Expect}; | 50 | use expect_test::{expect, Expect}; |
51 | use ide_db::helpers::FamousDefs; | ||
52 | 51 | ||
53 | use crate::{ | 52 | use crate::{ |
54 | test_utils::{self, completion_list}, | 53 | tests::{check_edit, filtered_completion_list}, |
55 | CompletionKind, | 54 | CompletionKind, |
56 | }; | 55 | }; |
57 | 56 | ||
58 | fn check(ra_fixture: &str, expect: Expect) { | 57 | fn check(ra_fixture: &str, expect: Expect) { |
59 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 58 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); |
60 | expect.assert_eq(&actual); | 59 | expect.assert_eq(&actual); |
61 | } | 60 | } |
62 | 61 | ||
63 | fn check_snippet(ra_fixture: &str, expect: Expect) { | 62 | fn check_snippet(ra_fixture: &str, expect: Expect) { |
64 | let actual = completion_list( | 63 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet); |
65 | &format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE), | ||
66 | CompletionKind::Snippet, | ||
67 | ); | ||
68 | expect.assert_eq(&actual); | 64 | expect.assert_eq(&actual); |
69 | } | 65 | } |
70 | 66 | ||
71 | fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
72 | test_utils::check_edit( | ||
73 | what, | ||
74 | &format!( | ||
75 | "//- /main.rs crate:main deps:core{}\n{}", | ||
76 | ra_fixture_before, | ||
77 | FamousDefs::FIXTURE, | ||
78 | ), | ||
79 | &(ra_fixture_after.to_owned() + "\n"), | ||
80 | ); | ||
81 | } | ||
82 | |||
83 | #[test] | 67 | #[test] |
84 | fn test_record_literal_field_default() { | 68 | fn test_record_literal_field_default() { |
85 | let test_code = r#" | 69 | let test_code = r#" |
70 | //- minicore: default | ||
86 | struct S { foo: u32, bar: usize } | 71 | struct S { foo: u32, bar: usize } |
87 | 72 | ||
88 | impl core::default::Default for S { | 73 | impl Default for S { |
89 | fn default() -> Self { | 74 | fn default() -> Self { |
90 | S { | 75 | S { |
91 | foo: 0, | 76 | foo: 0, |
@@ -121,9 +106,10 @@ fn process(f: S) { | |||
121 | check_edit( | 106 | check_edit( |
122 | "..Default::default()", | 107 | "..Default::default()", |
123 | r#" | 108 | r#" |
109 | //- minicore: default | ||
124 | struct S { foo: u32, bar: usize } | 110 | struct S { foo: u32, bar: usize } |
125 | 111 | ||
126 | impl core::default::Default for S { | 112 | impl Default for S { |
127 | fn default() -> Self { | 113 | fn default() -> Self { |
128 | S { | 114 | S { |
129 | foo: 0, | 115 | foo: 0, |
@@ -142,7 +128,7 @@ fn process(f: S) { | |||
142 | r#" | 128 | r#" |
143 | struct S { foo: u32, bar: usize } | 129 | struct S { foo: u32, bar: usize } |
144 | 130 | ||
145 | impl core::default::Default for S { | 131 | impl Default for S { |
146 | fn default() -> Self { | 132 | fn default() -> Self { |
147 | S { | 133 | S { |
148 | foo: 0, | 134 | foo: 0, |
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index b9862de67..cbc20cc2c 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! This file provides snippet completions, like `pd` => `eprintln!(...)`. | 1 | //! This file provides snippet completions, like `pd` => `eprintln!(...)`. |
2 | 2 | ||
3 | use ide_db::helpers::SnippetCap; | 3 | use ide_db::helpers::SnippetCap; |
4 | use syntax::T; | ||
4 | 5 | ||
5 | use crate::{ | 6 | use crate::{ |
6 | context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem, | 7 | context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem, |
@@ -35,9 +36,17 @@ pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte | |||
35 | } | 36 | } |
36 | 37 | ||
37 | pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 38 | pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { |
38 | if !ctx.expects_item() { | 39 | if !ctx.expects_item() |
40 | || ctx.previous_token_is(T![unsafe]) | ||
41 | || ctx.path_qual().is_some() | ||
42 | || ctx.has_impl_or_trait_prev_sibling() | ||
43 | { | ||
39 | return; | 44 | return; |
40 | } | 45 | } |
46 | if ctx.has_visibility_prev_sibling() { | ||
47 | return; // technically we could do some of these snippet completions if we were to put the | ||
48 | // attributes before the vis node. | ||
49 | } | ||
41 | let cap = match ctx.config.snippet_cap { | 50 | let cap = match ctx.config.snippet_cap { |
42 | Some(it) => it, | 51 | Some(it) => it, |
43 | None => return, | 52 | None => return, |
@@ -82,10 +91,10 @@ fn ${1:feature}() { | |||
82 | mod tests { | 91 | mod tests { |
83 | use expect_test::{expect, Expect}; | 92 | use expect_test::{expect, Expect}; |
84 | 93 | ||
85 | use crate::{test_utils::completion_list, CompletionKind}; | 94 | use crate::{tests::filtered_completion_list, CompletionKind}; |
86 | 95 | ||
87 | fn check(ra_fixture: &str, expect: Expect) { | 96 | fn check(ra_fixture: &str, expect: Expect) { |
88 | let actual = completion_list(ra_fixture, CompletionKind::Snippet); | 97 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet); |
89 | expect.assert_eq(&actual) | 98 | expect.assert_eq(&actual) |
90 | } | 99 | } |
91 | 100 | ||
@@ -105,21 +114,4 @@ mod tests { | |||
105 | check(r#"fn foo(x: i32) { ::foo$0 }"#, expect![[""]]); | 114 | check(r#"fn foo(x: i32) { ::foo$0 }"#, expect![[""]]); |
106 | check(r#"fn foo(x: i32) { ::$0 }"#, expect![[""]]); | 115 | check(r#"fn foo(x: i32) { ::$0 }"#, expect![[""]]); |
107 | } | 116 | } |
108 | |||
109 | #[test] | ||
110 | fn completes_snippets_in_items() { | ||
111 | check( | ||
112 | r#" | ||
113 | #[cfg(test)] | ||
114 | mod tests { | ||
115 | $0 | ||
116 | } | ||
117 | "#, | ||
118 | expect![[r#" | ||
119 | sn tmod (Test module) | ||
120 | sn tfn (Test function) | ||
121 | sn macro_rules | ||
122 | "#]], | ||
123 | ) | ||
124 | } | ||
125 | } | 117 | } |
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index a60e5f43c..65f0f3843 100644 --- a/crates/ide_completion/src/completions/trait_impl.rs +++ b/crates/ide_completion/src/completions/trait_impl.rs | |||
@@ -32,7 +32,7 @@ | |||
32 | //! ``` | 32 | //! ``` |
33 | 33 | ||
34 | use hir::{self, HasAttrs, HasSource}; | 34 | use hir::{self, HasAttrs, HasSource}; |
35 | use ide_db::{traits::get_missing_assoc_items, SymbolKind}; | 35 | use ide_db::{path_transform::PathTransform, traits::get_missing_assoc_items, SymbolKind}; |
36 | use syntax::{ | 36 | use syntax::{ |
37 | ast::{self, edit}, | 37 | ast::{self, edit}, |
38 | display::function_declaration, | 38 | display::function_declaration, |
@@ -52,24 +52,26 @@ enum ImplCompletionKind { | |||
52 | 52 | ||
53 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 53 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
54 | if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { | 54 | if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { |
55 | get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { | 55 | if let Some(hir_impl) = ctx.sema.to_def(&impl_def) { |
56 | hir::AssocItem::Function(fn_item) | 56 | get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { |
57 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => | 57 | hir::AssocItem::Function(fn_item) |
58 | { | 58 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => |
59 | add_function_impl(&trigger, acc, ctx, fn_item) | 59 | { |
60 | } | 60 | add_function_impl(&trigger, acc, ctx, fn_item, hir_impl) |
61 | hir::AssocItem::TypeAlias(type_item) | 61 | } |
62 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => | 62 | hir::AssocItem::TypeAlias(type_item) |
63 | { | 63 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => |
64 | add_type_alias_impl(&trigger, acc, ctx, type_item) | 64 | { |
65 | } | 65 | add_type_alias_impl(&trigger, acc, ctx, type_item) |
66 | hir::AssocItem::Const(const_item) | 66 | } |
67 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => | 67 | hir::AssocItem::Const(const_item) |
68 | { | 68 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => |
69 | add_const_impl(&trigger, acc, ctx, const_item) | 69 | { |
70 | } | 70 | add_const_impl(&trigger, acc, ctx, const_item, hir_impl) |
71 | _ => {} | 71 | } |
72 | }); | 72 | _ => {} |
73 | }); | ||
74 | } | ||
73 | } | 75 | } |
74 | } | 76 | } |
75 | 77 | ||
@@ -129,6 +131,7 @@ fn add_function_impl( | |||
129 | acc: &mut Completions, | 131 | acc: &mut Completions, |
130 | ctx: &CompletionContext, | 132 | ctx: &CompletionContext, |
131 | func: hir::Function, | 133 | func: hir::Function, |
134 | impl_def: hir::Impl, | ||
132 | ) { | 135 | ) { |
133 | let fn_name = func.name(ctx.db).to_string(); | 136 | let fn_name = func.name(ctx.db).to_string(); |
134 | 137 | ||
@@ -147,23 +150,55 @@ fn add_function_impl( | |||
147 | CompletionItemKind::SymbolKind(SymbolKind::Function) | 150 | CompletionItemKind::SymbolKind(SymbolKind::Function) |
148 | }; | 151 | }; |
149 | let range = replacement_range(ctx, fn_def_node); | 152 | let range = replacement_range(ctx, fn_def_node); |
150 | if let Some(src) = func.source(ctx.db) { | 153 | |
151 | let function_decl = function_declaration(&src.value); | 154 | if let Some(source) = func.source(ctx.db) { |
152 | match ctx.config.snippet_cap { | 155 | let assoc_item = ast::AssocItem::Fn(source.value); |
153 | Some(cap) => { | 156 | if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { |
154 | let snippet = format!("{} {{\n $0\n}}", function_decl); | 157 | let transformed_fn = match transformed_item { |
155 | item.snippet_edit(cap, TextEdit::replace(range, snippet)); | 158 | ast::AssocItem::Fn(func) => func, |
156 | } | 159 | _ => unreachable!(), |
157 | None => { | 160 | }; |
158 | let header = format!("{} {{", function_decl); | 161 | |
159 | item.text_edit(TextEdit::replace(range, header)); | 162 | let function_decl = function_declaration(&transformed_fn); |
160 | } | 163 | match ctx.config.snippet_cap { |
161 | }; | 164 | Some(cap) => { |
162 | item.kind(completion_kind); | 165 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
163 | item.add_to(acc); | 166 | item.snippet_edit(cap, TextEdit::replace(range, snippet)); |
167 | } | ||
168 | None => { | ||
169 | let header = format!("{} {{", function_decl); | ||
170 | item.text_edit(TextEdit::replace(range, header)); | ||
171 | } | ||
172 | }; | ||
173 | item.kind(completion_kind); | ||
174 | item.add_to(acc); | ||
175 | } | ||
164 | } | 176 | } |
165 | } | 177 | } |
166 | 178 | ||
179 | /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc. | ||
180 | fn get_transformed_assoc_item( | ||
181 | ctx: &CompletionContext, | ||
182 | assoc_item: ast::AssocItem, | ||
183 | impl_def: hir::Impl, | ||
184 | ) -> Option<ast::AssocItem> { | ||
185 | let assoc_item = assoc_item.clone_for_update(); | ||
186 | let trait_ = impl_def.trait_(ctx.db)?; | ||
187 | let source_scope = &ctx.sema.scope_for_def(trait_); | ||
188 | let target_scope = &ctx.sema.scope(impl_def.source(ctx.db)?.syntax().value); | ||
189 | let transform = PathTransform { | ||
190 | subst: (trait_, impl_def.source(ctx.db)?.value), | ||
191 | source_scope, | ||
192 | target_scope, | ||
193 | }; | ||
194 | |||
195 | transform.apply(assoc_item.clone()); | ||
196 | Some(match assoc_item { | ||
197 | ast::AssocItem::Fn(func) => ast::AssocItem::Fn(edit::remove_attrs_and_docs(&func)), | ||
198 | _ => assoc_item, | ||
199 | }) | ||
200 | } | ||
201 | |||
167 | fn add_type_alias_impl( | 202 | fn add_type_alias_impl( |
168 | type_def_node: &SyntaxNode, | 203 | type_def_node: &SyntaxNode, |
169 | acc: &mut Completions, | 204 | acc: &mut Completions, |
@@ -188,21 +223,30 @@ fn add_const_impl( | |||
188 | acc: &mut Completions, | 223 | acc: &mut Completions, |
189 | ctx: &CompletionContext, | 224 | ctx: &CompletionContext, |
190 | const_: hir::Const, | 225 | const_: hir::Const, |
226 | impl_def: hir::Impl, | ||
191 | ) { | 227 | ) { |
192 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); | 228 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); |
193 | 229 | ||
194 | if let Some(const_name) = const_name { | 230 | if let Some(const_name) = const_name { |
195 | if let Some(source) = const_.source(ctx.db) { | 231 | if let Some(source) = const_.source(ctx.db) { |
196 | let snippet = make_const_compl_syntax(&source.value); | 232 | let assoc_item = ast::AssocItem::Const(source.value); |
197 | 233 | if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { | |
198 | let range = replacement_range(ctx, const_def_node); | 234 | let transformed_const = match transformed_item { |
199 | let mut item = | 235 | ast::AssocItem::Const(const_) => const_, |
200 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | 236 | _ => unreachable!(), |
201 | item.text_edit(TextEdit::replace(range, snippet)) | 237 | }; |
202 | .lookup_by(const_name) | 238 | |
203 | .kind(SymbolKind::Const) | 239 | let snippet = make_const_compl_syntax(&transformed_const); |
204 | .set_documentation(const_.docs(ctx.db)); | 240 | |
205 | item.add_to(acc); | 241 | let range = replacement_range(ctx, const_def_node); |
242 | let mut item = | ||
243 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | ||
244 | item.text_edit(TextEdit::replace(range, snippet)) | ||
245 | .lookup_by(const_name) | ||
246 | .kind(SymbolKind::Const) | ||
247 | .set_documentation(const_.docs(ctx.db)); | ||
248 | item.add_to(acc); | ||
249 | } | ||
206 | } | 250 | } |
207 | } | 251 | } |
208 | } | 252 | } |
@@ -246,12 +290,12 @@ mod tests { | |||
246 | use expect_test::{expect, Expect}; | 290 | use expect_test::{expect, Expect}; |
247 | 291 | ||
248 | use crate::{ | 292 | use crate::{ |
249 | test_utils::{check_edit, completion_list}, | 293 | tests::{check_edit, filtered_completion_list}, |
250 | CompletionKind, | 294 | CompletionKind, |
251 | }; | 295 | }; |
252 | 296 | ||
253 | fn check(ra_fixture: &str, expect: Expect) { | 297 | fn check(ra_fixture: &str, expect: Expect) { |
254 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | 298 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); |
255 | expect.assert_eq(&actual) | 299 | expect.assert_eq(&actual) |
256 | } | 300 | } |
257 | 301 | ||
@@ -779,4 +823,183 @@ impl Foo for T {{ | |||
779 | test("Type", "type T$0", "type Type = "); | 823 | test("Type", "type T$0", "type Type = "); |
780 | test("CONST", "const C$0", "const CONST: i32 = "); | 824 | test("CONST", "const C$0", "const CONST: i32 = "); |
781 | } | 825 | } |
826 | |||
827 | #[test] | ||
828 | fn generics_are_inlined_in_return_type() { | ||
829 | check_edit( | ||
830 | "function", | ||
831 | r#" | ||
832 | trait Foo<T> { | ||
833 | fn function() -> T; | ||
834 | } | ||
835 | struct Bar; | ||
836 | |||
837 | impl Foo<u32> for Bar { | ||
838 | fn f$0 | ||
839 | } | ||
840 | "#, | ||
841 | r#" | ||
842 | trait Foo<T> { | ||
843 | fn function() -> T; | ||
844 | } | ||
845 | struct Bar; | ||
846 | |||
847 | impl Foo<u32> for Bar { | ||
848 | fn function() -> u32 { | ||
849 | $0 | ||
850 | } | ||
851 | } | ||
852 | "#, | ||
853 | ) | ||
854 | } | ||
855 | |||
856 | #[test] | ||
857 | fn generics_are_inlined_in_parameter() { | ||
858 | check_edit( | ||
859 | "function", | ||
860 | r#" | ||
861 | trait Foo<T> { | ||
862 | fn function(bar: T); | ||
863 | } | ||
864 | struct Bar; | ||
865 | |||
866 | impl Foo<u32> for Bar { | ||
867 | fn f$0 | ||
868 | } | ||
869 | "#, | ||
870 | r#" | ||
871 | trait Foo<T> { | ||
872 | fn function(bar: T); | ||
873 | } | ||
874 | struct Bar; | ||
875 | |||
876 | impl Foo<u32> for Bar { | ||
877 | fn function(bar: u32) { | ||
878 | $0 | ||
879 | } | ||
880 | } | ||
881 | "#, | ||
882 | ) | ||
883 | } | ||
884 | |||
885 | #[test] | ||
886 | fn generics_are_inlined_when_part_of_other_types() { | ||
887 | check_edit( | ||
888 | "function", | ||
889 | r#" | ||
890 | trait Foo<T> { | ||
891 | fn function(bar: Vec<T>); | ||
892 | } | ||
893 | struct Bar; | ||
894 | |||
895 | impl Foo<u32> for Bar { | ||
896 | fn f$0 | ||
897 | } | ||
898 | "#, | ||
899 | r#" | ||
900 | trait Foo<T> { | ||
901 | fn function(bar: Vec<T>); | ||
902 | } | ||
903 | struct Bar; | ||
904 | |||
905 | impl Foo<u32> for Bar { | ||
906 | fn function(bar: Vec<u32>) { | ||
907 | $0 | ||
908 | } | ||
909 | } | ||
910 | "#, | ||
911 | ) | ||
912 | } | ||
913 | |||
914 | #[test] | ||
915 | fn generics_are_inlined_complex() { | ||
916 | check_edit( | ||
917 | "function", | ||
918 | r#" | ||
919 | trait Foo<T, U, V> { | ||
920 | fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>; | ||
921 | } | ||
922 | struct Bar; | ||
923 | |||
924 | impl Foo<u32, Vec<usize>, u8> for Bar { | ||
925 | fn f$0 | ||
926 | } | ||
927 | "#, | ||
928 | r#" | ||
929 | trait Foo<T, U, V> { | ||
930 | fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>; | ||
931 | } | ||
932 | struct Bar; | ||
933 | |||
934 | impl Foo<u32, Vec<usize>, u8> for Bar { | ||
935 | fn function(bar: Vec<u32>, baz: Vec<usize>) -> Arc<Vec<u8>> { | ||
936 | $0 | ||
937 | } | ||
938 | } | ||
939 | "#, | ||
940 | ) | ||
941 | } | ||
942 | |||
943 | #[test] | ||
944 | fn generics_are_inlined_in_associated_const() { | ||
945 | check_edit( | ||
946 | "BAR", | ||
947 | r#" | ||
948 | trait Foo<T> { | ||
949 | const BAR: T; | ||
950 | } | ||
951 | struct Bar; | ||
952 | |||
953 | impl Foo<u32> for Bar { | ||
954 | const B$0; | ||
955 | } | ||
956 | "#, | ||
957 | r#" | ||
958 | trait Foo<T> { | ||
959 | const BAR: T; | ||
960 | } | ||
961 | struct Bar; | ||
962 | |||
963 | impl Foo<u32> for Bar { | ||
964 | const BAR: u32 = ; | ||
965 | } | ||
966 | "#, | ||
967 | ) | ||
968 | } | ||
969 | |||
970 | #[test] | ||
971 | fn generics_are_inlined_in_where_clause() { | ||
972 | check_edit( | ||
973 | "function", | ||
974 | r#" | ||
975 | trait SomeTrait<T> {} | ||
976 | |||
977 | trait Foo<T> { | ||
978 | fn function() | ||
979 | where Self: SomeTrait<T>; | ||
980 | } | ||
981 | struct Bar; | ||
982 | |||
983 | impl Foo<u32> for Bar { | ||
984 | fn f$0 | ||
985 | } | ||
986 | "#, | ||
987 | r#" | ||
988 | trait SomeTrait<T> {} | ||
989 | |||
990 | trait Foo<T> { | ||
991 | fn function() | ||
992 | where Self: SomeTrait<T>; | ||
993 | } | ||
994 | struct Bar; | ||
995 | |||
996 | impl Foo<u32> for Bar { | ||
997 | fn function() | ||
998 | where Self: SomeTrait<u32> { | ||
999 | $0 | ||
1000 | } | ||
1001 | } | ||
1002 | "#, | ||
1003 | ) | ||
1004 | } | ||
782 | } | 1005 | } |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 952f052a1..380c1e079 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -6,7 +6,7 @@ use syntax::{ast, AstNode}; | |||
6 | use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; | 6 | use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; |
7 | 7 | ||
8 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
9 | if ctx.is_path_disallowed() || !ctx.is_trivial_path() { | 9 | if ctx.is_path_disallowed() || !ctx.is_trivial_path() || ctx.has_impl_or_trait_prev_sibling() { |
10 | return; | 10 | return; |
11 | } | 11 | } |
12 | 12 | ||
@@ -25,7 +25,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
25 | return; | 25 | return; |
26 | } | 26 | } |
27 | 27 | ||
28 | if ctx.expects_use_tree() { | 28 | if ctx.in_use_tree() { |
29 | // only show modules in a fresh UseTree | 29 | // only show modules in a fresh UseTree |
30 | cov_mark::hit!(only_completes_modules_in_import); | 30 | cov_mark::hit!(only_completes_modules_in_import); |
31 | ctx.scope.process_all_names(&mut |name, res| { | 31 | ctx.scope.process_all_names(&mut |name, res| { |
@@ -36,12 +36,14 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
36 | return; | 36 | return; |
37 | } | 37 | } |
38 | 38 | ||
39 | if let Some(hir::Adt::Enum(e)) = | 39 | if !ctx.expects_type() { |
40 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) | 40 | if let Some(hir::Adt::Enum(e)) = |
41 | { | 41 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
42 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { | 42 | { |
43 | acc.add_qualified_enum_variant(ctx, variant, path) | 43 | super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { |
44 | }); | 44 | acc.add_qualified_enum_variant(ctx, variant, path) |
45 | }); | ||
46 | } | ||
45 | } | 47 | } |
46 | 48 | ||
47 | if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { | 49 | if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { |
@@ -59,12 +61,30 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
59 | } | 61 | } |
60 | 62 | ||
61 | ctx.scope.process_all_names(&mut |name, res| { | 63 | ctx.scope.process_all_names(&mut |name, res| { |
62 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { | 64 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) = |
65 | res | ||
66 | { | ||
63 | cov_mark::hit!(skip_lifetime_completion); | 67 | cov_mark::hit!(skip_lifetime_completion); |
64 | return; | 68 | return; |
65 | } | 69 | } |
66 | let add_resolution = match res { | 70 | let add_resolution = match res { |
71 | ScopeDef::ImplSelfType(_) => { | ||
72 | !ctx.previous_token_is(syntax::T![impl]) && !ctx.previous_token_is(syntax::T![for]) | ||
73 | } | ||
74 | // Don't suggest attribute macros and derives. | ||
67 | ScopeDef::MacroDef(mac) => mac.is_fn_like(), | 75 | ScopeDef::MacroDef(mac) => mac.is_fn_like(), |
76 | // no values in type places | ||
77 | ScopeDef::ModuleDef( | ||
78 | hir::ModuleDef::Function(_) | ||
79 | | hir::ModuleDef::Variant(_) | ||
80 | | hir::ModuleDef::Static(_), | ||
81 | ) | ||
82 | | ScopeDef::Local(_) => !ctx.expects_type(), | ||
83 | // unless its a constant in a generic arg list position | ||
84 | ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) | ||
85 | | ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => { | ||
86 | !ctx.expects_type() || ctx.expects_generic_arg() | ||
87 | } | ||
68 | _ => true, | 88 | _ => true, |
69 | }; | 89 | }; |
70 | if add_resolution { | 90 | if add_resolution { |
@@ -78,7 +98,7 @@ mod tests { | |||
78 | use expect_test::{expect, Expect}; | 98 | use expect_test::{expect, Expect}; |
79 | 99 | ||
80 | use crate::{ | 100 | use crate::{ |
81 | test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, | 101 | tests::{check_edit, filtered_completion_list_with_config, TEST_CONFIG}, |
82 | CompletionConfig, CompletionKind, | 102 | CompletionConfig, CompletionKind, |
83 | }; | 103 | }; |
84 | 104 | ||
@@ -87,99 +107,12 @@ mod tests { | |||
87 | } | 107 | } |
88 | 108 | ||
89 | fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { | 109 | fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { |
90 | let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference); | 110 | let actual = |
111 | filtered_completion_list_with_config(config, ra_fixture, CompletionKind::Reference); | ||
91 | expect.assert_eq(&actual) | 112 | expect.assert_eq(&actual) |
92 | } | 113 | } |
93 | 114 | ||
94 | #[test] | 115 | #[test] |
95 | fn dont_complete_values_in_type_pos() { | ||
96 | check( | ||
97 | r#" | ||
98 | const FOO: () = (); | ||
99 | static BAR: () = (); | ||
100 | enum Foo { | ||
101 | Bar | ||
102 | } | ||
103 | struct Baz; | ||
104 | fn foo() { | ||
105 | let local = (); | ||
106 | let _: $0; | ||
107 | } | ||
108 | "#, | ||
109 | expect![[r#" | ||
110 | en Foo | ||
111 | st Baz | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn only_completes_modules_in_import() { | ||
118 | cov_mark::check!(only_completes_modules_in_import); | ||
119 | check( | ||
120 | r#" | ||
121 | use f$0 | ||
122 | |||
123 | struct Foo; | ||
124 | mod foo {} | ||
125 | "#, | ||
126 | expect![[r#" | ||
127 | md foo | ||
128 | "#]], | ||
129 | ); | ||
130 | } | ||
131 | |||
132 | #[test] | ||
133 | fn bind_pat_and_path_ignore_at() { | ||
134 | check( | ||
135 | r#" | ||
136 | enum Enum { A, B } | ||
137 | fn quux(x: Option<Enum>) { | ||
138 | match x { | ||
139 | None => (), | ||
140 | Some(en$0 @ Enum::A) => (), | ||
141 | } | ||
142 | } | ||
143 | "#, | ||
144 | expect![[r#""#]], | ||
145 | ); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn bind_pat_and_path_ignore_ref() { | ||
150 | check( | ||
151 | r#" | ||
152 | enum Enum { A, B } | ||
153 | fn quux(x: Option<Enum>) { | ||
154 | match x { | ||
155 | None => (), | ||
156 | Some(ref en$0) => (), | ||
157 | } | ||
158 | } | ||
159 | "#, | ||
160 | expect![[r#""#]], | ||
161 | ); | ||
162 | } | ||
163 | |||
164 | #[test] | ||
165 | fn bind_pat_and_path() { | ||
166 | check( | ||
167 | r#" | ||
168 | enum Enum { A, B } | ||
169 | fn quux(x: Option<Enum>) { | ||
170 | match x { | ||
171 | None => (), | ||
172 | Some(En$0) => (), | ||
173 | } | ||
174 | } | ||
175 | "#, | ||
176 | expect![[r#" | ||
177 | en Enum | ||
178 | "#]], | ||
179 | ); | ||
180 | } | ||
181 | |||
182 | #[test] | ||
183 | fn completes_bindings_from_let() { | 116 | fn completes_bindings_from_let() { |
184 | check( | 117 | check( |
185 | r#" | 118 | r#" |
@@ -284,29 +217,6 @@ fn main() { | |||
284 | } | 217 | } |
285 | 218 | ||
286 | #[test] | 219 | #[test] |
287 | fn completes_generic_params_in_struct() { | ||
288 | check( | ||
289 | r#"struct S<T> { x: $0}"#, | ||
290 | expect![[r#" | ||
291 | sp Self | ||
292 | tp T | ||
293 | st S<…> | ||
294 | "#]], | ||
295 | ); | ||
296 | } | ||
297 | |||
298 | #[test] | ||
299 | fn completes_self_in_enum() { | ||
300 | check( | ||
301 | r#"enum X { Y($0) }"#, | ||
302 | expect![[r#" | ||
303 | sp Self | ||
304 | en X | ||
305 | "#]], | ||
306 | ); | ||
307 | } | ||
308 | |||
309 | #[test] | ||
310 | fn completes_module_items() { | 220 | fn completes_module_items() { |
311 | check( | 221 | check( |
312 | r#" | 222 | r#" |
@@ -343,22 +253,6 @@ fn _alpha() {} | |||
343 | } | 253 | } |
344 | 254 | ||
345 | #[test] | 255 | #[test] |
346 | fn completes_extern_prelude() { | ||
347 | check( | ||
348 | r#" | ||
349 | //- /lib.rs crate:main deps:other_crate | ||
350 | use $0; | ||
351 | |||
352 | //- /other_crate/lib.rs crate:other_crate | ||
353 | // nothing here | ||
354 | "#, | ||
355 | expect![[r#" | ||
356 | md other_crate | ||
357 | "#]], | ||
358 | ); | ||
359 | } | ||
360 | |||
361 | #[test] | ||
362 | fn completes_module_items_in_nested_modules() { | 256 | fn completes_module_items_in_nested_modules() { |
363 | check( | 257 | check( |
364 | r#" | 258 | r#" |
@@ -376,19 +270,6 @@ mod m { | |||
376 | } | 270 | } |
377 | 271 | ||
378 | #[test] | 272 | #[test] |
379 | fn completes_return_type() { | ||
380 | check( | ||
381 | r#" | ||
382 | struct Foo; | ||
383 | fn x() -> $0 | ||
384 | "#, | ||
385 | expect![[r#" | ||
386 | st Foo | ||
387 | "#]], | ||
388 | ); | ||
389 | } | ||
390 | |||
391 | #[test] | ||
392 | fn dont_show_both_completions_for_shadowing() { | 273 | fn dont_show_both_completions_for_shadowing() { |
393 | check( | 274 | check( |
394 | r#" | 275 | r#" |
@@ -485,18 +366,6 @@ fn f() {$0} | |||
485 | check( | 366 | check( |
486 | r#" | 367 | r#" |
487 | #[rustc_builtin_macro] | 368 | #[rustc_builtin_macro] |
488 | pub macro Clone {} | ||
489 | |||
490 | struct S; | ||
491 | impl S { | ||
492 | $0 | ||
493 | } | ||
494 | "#, | ||
495 | expect![[r#""#]], | ||
496 | ); | ||
497 | check( | ||
498 | r#" | ||
499 | #[rustc_builtin_macro] | ||
500 | pub macro bench {} | 369 | pub macro bench {} |
501 | 370 | ||
502 | fn f() {$0} | 371 | fn f() {$0} |
@@ -582,19 +451,6 @@ fn foo() { $0 } | |||
582 | } | 451 | } |
583 | 452 | ||
584 | #[test] | 453 | #[test] |
585 | fn completes_macros_as_type() { | ||
586 | check( | ||
587 | r#" | ||
588 | macro_rules! foo { () => {} } | ||
589 | fn main() { let x: $0 } | ||
590 | "#, | ||
591 | expect![[r#" | ||
592 | ma foo!(…) macro_rules! foo | ||
593 | "#]], | ||
594 | ); | ||
595 | } | ||
596 | |||
597 | #[test] | ||
598 | fn completes_macros_as_stmt() { | 454 | fn completes_macros_as_stmt() { |
599 | check( | 455 | check( |
600 | r#" | 456 | r#" |
@@ -739,74 +595,4 @@ fn f() {} | |||
739 | expect![[""]], | 595 | expect![[""]], |
740 | ) | 596 | ) |
741 | } | 597 | } |
742 | |||
743 | #[test] | ||
744 | fn completes_target_type_or_trait_in_impl_block() { | ||
745 | check( | ||
746 | r#" | ||
747 | trait MyTrait {} | ||
748 | struct MyStruct {} | ||
749 | |||
750 | impl My$0 | ||
751 | "#, | ||
752 | expect![[r#" | ||
753 | sp Self | ||
754 | tt MyTrait | ||
755 | st MyStruct | ||
756 | "#]], | ||
757 | ) | ||
758 | } | ||
759 | |||
760 | #[test] | ||
761 | fn completes_in_assoc_item_list() { | ||
762 | check( | ||
763 | r#" | ||
764 | macro_rules! foo {} | ||
765 | mod bar {} | ||
766 | |||
767 | struct MyStruct {} | ||
768 | impl MyStruct { | ||
769 | $0 | ||
770 | } | ||
771 | "#, | ||
772 | expect![[r#" | ||
773 | md bar | ||
774 | ma foo!(…) macro_rules! foo | ||
775 | "#]], | ||
776 | ) | ||
777 | } | ||
778 | |||
779 | #[test] | ||
780 | fn completes_in_item_list() { | ||
781 | check( | ||
782 | r#" | ||
783 | struct MyStruct {} | ||
784 | macro_rules! foo {} | ||
785 | mod bar {} | ||
786 | |||
787 | $0 | ||
788 | "#, | ||
789 | expect![[r#" | ||
790 | md bar | ||
791 | ma foo!(…) macro_rules! foo | ||
792 | "#]], | ||
793 | ) | ||
794 | } | ||
795 | |||
796 | #[test] | ||
797 | fn completes_assoc_types_in_dynimpl_trait() { | ||
798 | check( | ||
799 | r#" | ||
800 | trait Foo { | ||
801 | type Bar; | ||
802 | } | ||
803 | |||
804 | fn foo(_: impl Foo<B$0>) {} | ||
805 | "#, | ||
806 | expect![[r#" | ||
807 | ta Bar = type Bar; | ||
808 | tt Foo | ||
809 | "#]], | ||
810 | ); | ||
811 | } | ||
812 | } | 598 | } |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 4c3929a26..f0da98739 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -43,6 +43,8 @@ pub(crate) struct PathCompletionContext { | |||
43 | pub(super) is_trivial_path: bool, | 43 | pub(super) is_trivial_path: bool, |
44 | /// If not a trivial path, the prefix (qualifier). | 44 | /// If not a trivial path, the prefix (qualifier). |
45 | pub(super) qualifier: Option<ast::Path>, | 45 | pub(super) qualifier: Option<ast::Path>, |
46 | /// Whether the qualifier comes from a use tree parent or not | ||
47 | pub(super) use_tree_parent: bool, | ||
46 | pub(super) kind: Option<PathKind>, | 48 | pub(super) kind: Option<PathKind>, |
47 | /// Whether the path segment has type args or not. | 49 | /// Whether the path segment has type args or not. |
48 | pub(super) has_type_args: bool, | 50 | pub(super) has_type_args: bool, |
@@ -79,7 +81,6 @@ pub(crate) struct CompletionContext<'a> { | |||
79 | /// The parent impl of the cursor position if it exists. | 81 | /// The parent impl of the cursor position if it exists. |
80 | pub(super) impl_def: Option<ast::Impl>, | 82 | pub(super) impl_def: Option<ast::Impl>, |
81 | pub(super) name_ref_syntax: Option<ast::NameRef>, | 83 | pub(super) name_ref_syntax: Option<ast::NameRef>, |
82 | pub(super) use_item_syntax: Option<ast::Use>, | ||
83 | 84 | ||
84 | // potentially set if we are completing a lifetime | 85 | // potentially set if we are completing a lifetime |
85 | pub(super) lifetime_syntax: Option<ast::Lifetime>, | 86 | pub(super) lifetime_syntax: Option<ast::Lifetime>, |
@@ -151,7 +152,6 @@ impl<'a> CompletionContext<'a> { | |||
151 | function_def: None, | 152 | function_def: None, |
152 | impl_def: None, | 153 | impl_def: None, |
153 | name_ref_syntax: None, | 154 | name_ref_syntax: None, |
154 | use_item_syntax: None, | ||
155 | lifetime_syntax: None, | 155 | lifetime_syntax: None, |
156 | lifetime_param_syntax: None, | 156 | lifetime_param_syntax: None, |
157 | lifetime_allowed: false, | 157 | lifetime_allowed: false, |
@@ -242,32 +242,27 @@ impl<'a> CompletionContext<'a> { | |||
242 | } | 242 | } |
243 | 243 | ||
244 | pub(crate) fn expects_assoc_item(&self) -> bool { | 244 | pub(crate) fn expects_assoc_item(&self) -> bool { |
245 | matches!( | 245 | matches!(self.completion_location, Some(ImmediateLocation::Trait | ImmediateLocation::Impl)) |
246 | self.completion_location, | ||
247 | Some(ImmediateLocation::Trait) | Some(ImmediateLocation::Impl) | ||
248 | ) | ||
249 | } | 246 | } |
250 | 247 | ||
251 | pub(crate) fn has_dot_receiver(&self) -> bool { | 248 | pub(crate) fn has_dot_receiver(&self) -> bool { |
252 | matches!( | 249 | matches!( |
253 | &self.completion_location, | 250 | &self.completion_location, |
254 | Some(ImmediateLocation::FieldAccess { receiver, .. }) | Some(ImmediateLocation::MethodCall { receiver,.. }) | 251 | Some(ImmediateLocation::FieldAccess { receiver, .. } | ImmediateLocation::MethodCall { receiver,.. }) |
255 | if receiver.is_some() | 252 | if receiver.is_some() |
256 | ) | 253 | ) |
257 | } | 254 | } |
258 | 255 | ||
259 | pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { | 256 | pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { |
260 | match &self.completion_location { | 257 | match &self.completion_location { |
261 | Some(ImmediateLocation::MethodCall { receiver, .. }) | 258 | Some( |
262 | | Some(ImmediateLocation::FieldAccess { receiver, .. }) => receiver.as_ref(), | 259 | ImmediateLocation::MethodCall { receiver, .. } |
260 | | ImmediateLocation::FieldAccess { receiver, .. }, | ||
261 | ) => receiver.as_ref(), | ||
263 | _ => None, | 262 | _ => None, |
264 | } | 263 | } |
265 | } | 264 | } |
266 | 265 | ||
267 | pub(crate) fn expects_use_tree(&self) -> bool { | ||
268 | matches!(self.completion_location, Some(ImmediateLocation::Use)) | ||
269 | } | ||
270 | |||
271 | pub(crate) fn expects_non_trait_assoc_item(&self) -> bool { | 266 | pub(crate) fn expects_non_trait_assoc_item(&self) -> bool { |
272 | matches!(self.completion_location, Some(ImmediateLocation::Impl)) | 267 | matches!(self.completion_location, Some(ImmediateLocation::Impl)) |
273 | } | 268 | } |
@@ -276,6 +271,10 @@ impl<'a> CompletionContext<'a> { | |||
276 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) | 271 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) |
277 | } | 272 | } |
278 | 273 | ||
274 | pub(crate) fn expects_generic_arg(&self) -> bool { | ||
275 | matches!(self.completion_location, Some(ImmediateLocation::GenericArgList(_))) | ||
276 | } | ||
277 | |||
279 | pub(crate) fn has_block_expr_parent(&self) -> bool { | 278 | pub(crate) fn has_block_expr_parent(&self) -> bool { |
280 | matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) | 279 | matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) |
281 | } | 280 | } |
@@ -283,33 +282,59 @@ impl<'a> CompletionContext<'a> { | |||
283 | pub(crate) fn expects_ident_pat_or_ref_expr(&self) -> bool { | 282 | pub(crate) fn expects_ident_pat_or_ref_expr(&self) -> bool { |
284 | matches!( | 283 | matches!( |
285 | self.completion_location, | 284 | self.completion_location, |
286 | Some(ImmediateLocation::IdentPat) | Some(ImmediateLocation::RefExpr) | 285 | Some(ImmediateLocation::IdentPat | ImmediateLocation::RefExpr) |
287 | ) | 286 | ) |
288 | } | 287 | } |
289 | 288 | ||
290 | pub(crate) fn expect_record_field(&self) -> bool { | 289 | pub(crate) fn expect_field(&self) -> bool { |
291 | matches!(self.completion_location, Some(ImmediateLocation::RecordField)) | 290 | matches!( |
291 | self.completion_location, | ||
292 | Some(ImmediateLocation::RecordField | ImmediateLocation::TupleField) | ||
293 | ) | ||
294 | } | ||
295 | |||
296 | pub(crate) fn in_use_tree(&self) -> bool { | ||
297 | matches!( | ||
298 | self.completion_location, | ||
299 | Some(ImmediateLocation::Use | ImmediateLocation::UseTree) | ||
300 | ) | ||
292 | } | 301 | } |
293 | 302 | ||
294 | pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { | 303 | pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { |
295 | matches!( | 304 | matches!( |
296 | self.prev_sibling, | 305 | self.prev_sibling, |
297 | Some(ImmediatePrevSibling::ImplDefType) | Some(ImmediatePrevSibling::TraitDefName) | 306 | Some(ImmediatePrevSibling::ImplDefType | ImmediatePrevSibling::TraitDefName) |
298 | ) | 307 | ) |
299 | } | 308 | } |
300 | 309 | ||
310 | pub(crate) fn has_impl_prev_sibling(&self) -> bool { | ||
311 | matches!(self.prev_sibling, Some(ImmediatePrevSibling::ImplDefType)) | ||
312 | } | ||
313 | |||
314 | pub(crate) fn has_visibility_prev_sibling(&self) -> bool { | ||
315 | matches!(self.prev_sibling, Some(ImmediatePrevSibling::Visibility)) | ||
316 | } | ||
317 | |||
301 | pub(crate) fn after_if(&self) -> bool { | 318 | pub(crate) fn after_if(&self) -> bool { |
302 | matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr)) | 319 | matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr)) |
303 | } | 320 | } |
304 | 321 | ||
305 | pub(crate) fn is_path_disallowed(&self) -> bool { | 322 | pub(crate) fn is_path_disallowed(&self) -> bool { |
306 | matches!( | 323 | self.attribute_under_caret.is_some() |
307 | self.completion_location, | 324 | || self.previous_token_is(T![unsafe]) |
308 | Some(ImmediateLocation::Attribute(_)) | 325 | || matches!( |
309 | | Some(ImmediateLocation::ModDeclaration(_)) | 326 | self.prev_sibling, |
310 | | Some(ImmediateLocation::RecordPat(_)) | 327 | Some(ImmediatePrevSibling::Attribute | ImmediatePrevSibling::Visibility) |
311 | | Some(ImmediateLocation::RecordExpr(_)) | 328 | ) |
312 | ) || self.attribute_under_caret.is_some() | 329 | || matches!( |
330 | self.completion_location, | ||
331 | Some( | ||
332 | ImmediateLocation::Attribute(_) | ||
333 | | ImmediateLocation::ModDeclaration(_) | ||
334 | | ImmediateLocation::RecordPat(_) | ||
335 | | ImmediateLocation::RecordExpr(_) | ||
336 | ) | ||
337 | ) | ||
313 | } | 338 | } |
314 | 339 | ||
315 | pub(crate) fn expects_expression(&self) -> bool { | 340 | pub(crate) fn expects_expression(&self) -> bool { |
@@ -363,14 +388,19 @@ impl<'a> CompletionContext<'a> { | |||
363 | (ty, name) | 388 | (ty, name) |
364 | }, | 389 | }, |
365 | ast::ArgList(_it) => { | 390 | ast::ArgList(_it) => { |
366 | cov_mark::hit!(expected_type_fn_param_with_leading_char); | 391 | cov_mark::hit!(expected_type_fn_param); |
367 | cov_mark::hit!(expected_type_fn_param_without_leading_char); | ||
368 | ActiveParameter::at_token( | 392 | ActiveParameter::at_token( |
369 | &self.sema, | 393 | &self.sema, |
370 | self.token.clone(), | 394 | self.token.clone(), |
371 | ).map(|ap| { | 395 | ).map(|ap| { |
372 | let name = ap.ident().map(NameOrNameRef::Name); | 396 | let name = ap.ident().map(NameOrNameRef::Name); |
373 | (Some(ap.ty), name) | 397 | let ty = if has_ref(&self.token) { |
398 | cov_mark::hit!(expected_type_fn_param_ref); | ||
399 | ap.ty.remove_ref() | ||
400 | } else { | ||
401 | Some(ap.ty) | ||
402 | }; | ||
403 | (ty, name) | ||
374 | }) | 404 | }) |
375 | .unwrap_or((None, None)) | 405 | .unwrap_or((None, None)) |
376 | }, | 406 | }, |
@@ -564,9 +594,6 @@ impl<'a> CompletionContext<'a> { | |||
564 | self.name_ref_syntax = | 594 | self.name_ref_syntax = |
565 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); | 595 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); |
566 | 596 | ||
567 | self.use_item_syntax = | ||
568 | self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast); | ||
569 | |||
570 | self.function_def = self | 597 | self.function_def = self |
571 | .sema | 598 | .sema |
572 | .token_ancestors_with_macros(self.token.clone()) | 599 | .token_ancestors_with_macros(self.token.clone()) |
@@ -586,6 +613,7 @@ impl<'a> CompletionContext<'a> { | |||
586 | has_type_args: false, | 613 | has_type_args: false, |
587 | can_be_stmt: false, | 614 | can_be_stmt: false, |
588 | in_loop_body: false, | 615 | in_loop_body: false, |
616 | use_tree_parent: false, | ||
589 | kind: None, | 617 | kind: None, |
590 | }); | 618 | }); |
591 | path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); | 619 | path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); |
@@ -613,7 +641,8 @@ impl<'a> CompletionContext<'a> { | |||
613 | } | 641 | } |
614 | path_ctx.has_type_args = segment.generic_arg_list().is_some(); | 642 | path_ctx.has_type_args = segment.generic_arg_list().is_some(); |
615 | 643 | ||
616 | if let Some(path) = path_or_use_tree_qualifier(&path) { | 644 | if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) { |
645 | path_ctx.use_tree_parent = use_tree_parent; | ||
617 | path_ctx.qualifier = path | 646 | path_ctx.qualifier = path |
618 | .segment() | 647 | .segment() |
619 | .and_then(|it| { | 648 | .and_then(|it| { |
@@ -667,13 +696,26 @@ fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { | |||
667 | } | 696 | } |
668 | } | 697 | } |
669 | 698 | ||
670 | fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> { | 699 | fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> { |
671 | if let Some(qual) = path.qualifier() { | 700 | if let Some(qual) = path.qualifier() { |
672 | return Some(qual); | 701 | return Some((qual, false)); |
673 | } | 702 | } |
674 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; | 703 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; |
675 | let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; | 704 | let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; |
676 | use_tree.path() | 705 | use_tree.path().zip(Some(true)) |
706 | } | ||
707 | |||
708 | fn has_ref(token: &SyntaxToken) -> bool { | ||
709 | let mut token = token.clone(); | ||
710 | for skip in [WHITESPACE, IDENT, T![mut]] { | ||
711 | if token.kind() == skip { | ||
712 | token = match token.prev_token() { | ||
713 | Some(it) => it, | ||
714 | None => return false, | ||
715 | } | ||
716 | } | ||
717 | } | ||
718 | token.kind() == T![&] | ||
677 | } | 719 | } |
678 | 720 | ||
679 | #[cfg(test)] | 721 | #[cfg(test)] |
@@ -681,7 +723,7 @@ mod tests { | |||
681 | use expect_test::{expect, Expect}; | 723 | use expect_test::{expect, Expect}; |
682 | use hir::HirDisplay; | 724 | use hir::HirDisplay; |
683 | 725 | ||
684 | use crate::test_utils::{position, TEST_CONFIG}; | 726 | use crate::tests::{position, TEST_CONFIG}; |
685 | 727 | ||
686 | use super::CompletionContext; | 728 | use super::CompletionContext; |
687 | 729 | ||
@@ -748,14 +790,18 @@ fn foo() { | |||
748 | } | 790 | } |
749 | 791 | ||
750 | #[test] | 792 | #[test] |
751 | fn expected_type_fn_param_without_leading_char() { | 793 | fn expected_type_fn_param() { |
752 | cov_mark::check!(expected_type_fn_param_without_leading_char); | 794 | cov_mark::check!(expected_type_fn_param); |
753 | check_expected_type_and_name( | 795 | check_expected_type_and_name( |
754 | r#" | 796 | r#" |
755 | fn foo() { | 797 | fn foo() { bar($0); } |
756 | bar($0); | 798 | fn bar(x: u32) {} |
757 | } | 799 | "#, |
758 | 800 | expect![[r#"ty: u32, name: x"#]], | |
801 | ); | ||
802 | check_expected_type_and_name( | ||
803 | r#" | ||
804 | fn foo() { bar(c$0); } | ||
759 | fn bar(x: u32) {} | 805 | fn bar(x: u32) {} |
760 | "#, | 806 | "#, |
761 | expect![[r#"ty: u32, name: x"#]], | 807 | expect![[r#"ty: u32, name: x"#]], |
@@ -763,18 +809,29 @@ fn bar(x: u32) {} | |||
763 | } | 809 | } |
764 | 810 | ||
765 | #[test] | 811 | #[test] |
766 | fn expected_type_fn_param_with_leading_char() { | 812 | fn expected_type_fn_param_ref() { |
767 | cov_mark::check!(expected_type_fn_param_with_leading_char); | 813 | cov_mark::check!(expected_type_fn_param_ref); |
768 | check_expected_type_and_name( | 814 | check_expected_type_and_name( |
769 | r#" | 815 | r#" |
770 | fn foo() { | 816 | fn foo() { bar(&$0); } |
771 | bar(c$0); | 817 | fn bar(x: &u32) {} |
772 | } | 818 | "#, |
773 | 819 | expect![[r#"ty: u32, name: x"#]], | |
774 | fn bar(x: u32) {} | 820 | ); |
821 | check_expected_type_and_name( | ||
822 | r#" | ||
823 | fn foo() { bar(&mut $0); } | ||
824 | fn bar(x: &mut u32) {} | ||
775 | "#, | 825 | "#, |
776 | expect![[r#"ty: u32, name: x"#]], | 826 | expect![[r#"ty: u32, name: x"#]], |
777 | ); | 827 | ); |
828 | check_expected_type_and_name( | ||
829 | r#" | ||
830 | fn foo() { bar(&c$0); } | ||
831 | fn bar(x: &u32) {} | ||
832 | "#, | ||
833 | expect![[r#"ty: u32, name: x"#]], | ||
834 | ); | ||
778 | } | 835 | } |
779 | 836 | ||
780 | #[test] | 837 | #[test] |
@@ -921,13 +978,12 @@ fn foo() -> u32 { | |||
921 | // FIXME: make this work with `|| $0` | 978 | // FIXME: make this work with `|| $0` |
922 | check_expected_type_and_name( | 979 | check_expected_type_and_name( |
923 | r#" | 980 | r#" |
981 | //- minicore: fn | ||
924 | fn foo() { | 982 | fn foo() { |
925 | bar(|| a$0); | 983 | bar(|| a$0); |
926 | } | 984 | } |
927 | 985 | ||
928 | fn bar(f: impl FnOnce() -> u32) {} | 986 | fn bar(f: impl FnOnce() -> u32) {} |
929 | #[lang = "fn_once"] | ||
930 | trait FnOnce { type Output; } | ||
931 | "#, | 987 | "#, |
932 | expect![[r#"ty: u32, name: ?"#]], | 988 | expect![[r#"ty: u32, name: ?"#]], |
933 | ); | 989 | ); |
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs index 99edb9499..ae63d132e 100644 --- a/crates/ide_completion/src/item.rs +++ b/crates/ide_completion/src/item.rs | |||
@@ -378,7 +378,7 @@ impl ImportEdit { | |||
378 | let _p = profile::span("ImportEdit::to_text_edit"); | 378 | let _p = profile::span("ImportEdit::to_text_edit"); |
379 | 379 | ||
380 | let new_ast = self.scope.clone_for_update(); | 380 | let new_ast = self.scope.clone_for_update(); |
381 | insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), cfg); | 381 | insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), &cfg); |
382 | let mut import_insert = TextEdit::builder(); | 382 | let mut import_insert = TextEdit::builder(); |
383 | algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node()) | 383 | algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node()) |
384 | .into_text_edit(&mut import_insert); | 384 | .into_text_edit(&mut import_insert); |
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 18983aa01..bf73818dc 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -1,14 +1,14 @@ | |||
1 | //! `completions` crate provides utilities for generating completions of user input. | 1 | //! `completions` crate provides utilities for generating completions of user input. |
2 | 2 | ||
3 | mod completions; | ||
3 | mod config; | 4 | mod config; |
4 | mod item; | ||
5 | mod context; | 5 | mod context; |
6 | mod item; | ||
6 | mod patterns; | 7 | mod patterns; |
7 | #[cfg(test)] | ||
8 | mod test_utils; | ||
9 | mod render; | 8 | mod render; |
10 | 9 | ||
11 | mod completions; | 10 | #[cfg(test)] |
11 | mod tests; | ||
12 | 12 | ||
13 | use completions::flyimport::position_for_import; | 13 | use completions::flyimport::position_for_import; |
14 | use ide_db::{ | 14 | use ide_db::{ |
@@ -141,6 +141,7 @@ pub fn completions( | |||
141 | let ctx = CompletionContext::new(db, position, config)?; | 141 | let ctx = CompletionContext::new(db, position, config)?; |
142 | 142 | ||
143 | if ctx.no_completion_required() { | 143 | if ctx.no_completion_required() { |
144 | cov_mark::hit!(no_completion_required); | ||
144 | // No work required here. | 145 | // No work required here. |
145 | return None; | 146 | return None; |
146 | } | 147 | } |
@@ -200,117 +201,3 @@ pub fn resolve_completion_edits( | |||
200 | 201 | ||
201 | ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit]) | 202 | ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit]) |
202 | } | 203 | } |
203 | |||
204 | #[cfg(test)] | ||
205 | mod tests { | ||
206 | use crate::test_utils::{self, TEST_CONFIG}; | ||
207 | |||
208 | struct DetailAndDocumentation<'a> { | ||
209 | detail: &'a str, | ||
210 | documentation: &'a str, | ||
211 | } | ||
212 | |||
213 | fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) { | ||
214 | let (db, position) = test_utils::position(ra_fixture); | ||
215 | let config = TEST_CONFIG; | ||
216 | let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into(); | ||
217 | for item in completions { | ||
218 | if item.detail() == Some(expected.detail) { | ||
219 | let opt = item.documentation(); | ||
220 | let doc = opt.as_ref().map(|it| it.as_str()); | ||
221 | assert_eq!(doc, Some(expected.documentation)); | ||
222 | return; | ||
223 | } | ||
224 | } | ||
225 | panic!("completion detail not found: {}", expected.detail) | ||
226 | } | ||
227 | |||
228 | fn check_no_completion(ra_fixture: &str) { | ||
229 | let (db, position) = test_utils::position(ra_fixture); | ||
230 | let config = TEST_CONFIG; | ||
231 | |||
232 | let completions: Option<Vec<String>> = crate::completions(&db, &config, position) | ||
233 | .and_then(|completions| { | ||
234 | let completions: Vec<_> = completions.into(); | ||
235 | if completions.is_empty() { | ||
236 | None | ||
237 | } else { | ||
238 | Some(completions) | ||
239 | } | ||
240 | }) | ||
241 | .map(|completions| { | ||
242 | completions.into_iter().map(|completion| format!("{:?}", completion)).collect() | ||
243 | }); | ||
244 | |||
245 | // `assert_eq` instead of `assert!(completions.is_none())` to get the list of completions if test will panic. | ||
246 | assert_eq!(completions, None, "Completions were generated, but weren't expected"); | ||
247 | } | ||
248 | |||
249 | #[test] | ||
250 | fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() { | ||
251 | check_detail_and_documentation( | ||
252 | r#" | ||
253 | macro_rules! bar { | ||
254 | () => { | ||
255 | struct Bar; | ||
256 | impl Bar { | ||
257 | #[doc = "Do the foo"] | ||
258 | fn foo(&self) {} | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | |||
263 | bar!(); | ||
264 | |||
265 | fn foo() { | ||
266 | let bar = Bar; | ||
267 | bar.fo$0; | ||
268 | } | ||
269 | "#, | ||
270 | DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" }, | ||
271 | ); | ||
272 | } | ||
273 | |||
274 | #[test] | ||
275 | fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() { | ||
276 | check_detail_and_documentation( | ||
277 | r#" | ||
278 | macro_rules! bar { | ||
279 | () => { | ||
280 | struct Bar; | ||
281 | impl Bar { | ||
282 | /// Do the foo | ||
283 | fn foo(&self) {} | ||
284 | } | ||
285 | } | ||
286 | } | ||
287 | |||
288 | bar!(); | ||
289 | |||
290 | fn foo() { | ||
291 | let bar = Bar; | ||
292 | bar.fo$0; | ||
293 | } | ||
294 | "#, | ||
295 | DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" }, | ||
296 | ); | ||
297 | } | ||
298 | |||
299 | #[test] | ||
300 | fn test_no_completions_required() { | ||
301 | // There must be no hint for 'in' keyword. | ||
302 | check_no_completion(r#"fn foo() { for i i$0 }"#); | ||
303 | // After 'in' keyword hints may be spawned. | ||
304 | check_detail_and_documentation( | ||
305 | r#" | ||
306 | /// Do the foo | ||
307 | fn foo() -> &'static str { "foo" } | ||
308 | |||
309 | fn bar() { | ||
310 | for c in fo$0 | ||
311 | } | ||
312 | "#, | ||
313 | DetailAndDocumentation { detail: "fn() -> &str", documentation: "Do the foo" }, | ||
314 | ); | ||
315 | } | ||
316 | } | ||
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 72e67e3c4..757c9a3da 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -11,7 +11,7 @@ use syntax::{ | |||
11 | }; | 11 | }; |
12 | 12 | ||
13 | #[cfg(test)] | 13 | #[cfg(test)] |
14 | use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; | 14 | use crate::tests::{check_pattern_is_applicable, check_pattern_is_not_applicable}; |
15 | 15 | ||
16 | /// Immediate previous node to what we are completing. | 16 | /// Immediate previous node to what we are completing. |
17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
@@ -19,15 +19,19 @@ pub(crate) enum ImmediatePrevSibling { | |||
19 | IfExpr, | 19 | IfExpr, |
20 | TraitDefName, | 20 | TraitDefName, |
21 | ImplDefType, | 21 | ImplDefType, |
22 | Visibility, | ||
23 | Attribute, | ||
22 | } | 24 | } |
23 | 25 | ||
24 | /// Direct parent "thing" of what we are currently completing. | 26 | /// Direct parent "thing" of what we are currently completing. |
25 | #[derive(Clone, Debug, PartialEq, Eq)] | 27 | #[derive(Clone, Debug, PartialEq, Eq)] |
26 | pub(crate) enum ImmediateLocation { | 28 | pub(crate) enum ImmediateLocation { |
27 | Use, | 29 | Use, |
30 | UseTree, | ||
28 | Impl, | 31 | Impl, |
29 | Trait, | 32 | Trait, |
30 | RecordField, | 33 | RecordField, |
34 | TupleField, | ||
31 | RefExpr, | 35 | RefExpr, |
32 | IdentPat, | 36 | IdentPat, |
33 | BlockExpr, | 37 | BlockExpr, |
@@ -79,6 +83,17 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi | |||
79 | _ => node, | 83 | _ => node, |
80 | }; | 84 | }; |
81 | let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; | 85 | let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; |
86 | if prev_sibling.kind() == ERROR { | ||
87 | let prev_sibling = prev_sibling.first_child()?; | ||
88 | let res = match_ast! { | ||
89 | match prev_sibling { | ||
90 | // vis followed by random ident will always error the parser | ||
91 | ast::Visibility(_it) => ImmediatePrevSibling::Visibility, | ||
92 | _ => return None, | ||
93 | } | ||
94 | }; | ||
95 | return Some(res); | ||
96 | } | ||
82 | let res = match_ast! { | 97 | let res = match_ast! { |
83 | match prev_sibling { | 98 | match prev_sibling { |
84 | ast::ExprStmt(it) => { | 99 | ast::ExprStmt(it) => { |
@@ -101,6 +116,7 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi | |||
101 | } else { | 116 | } else { |
102 | return None | 117 | return None |
103 | }, | 118 | }, |
119 | ast::Attr(_it) => ImmediatePrevSibling::Attribute, | ||
104 | _ => return None, | 120 | _ => return None, |
105 | } | 121 | } |
106 | }; | 122 | }; |
@@ -166,11 +182,19 @@ pub(crate) fn determine_location( | |||
166 | match parent { | 182 | match parent { |
167 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, | 183 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, |
168 | ast::Use(_it) => ImmediateLocation::Use, | 184 | ast::Use(_it) => ImmediateLocation::Use, |
185 | ast::UseTree(_it) => ImmediateLocation::UseTree, | ||
186 | ast::UseTreeList(_it) => ImmediateLocation::UseTree, | ||
169 | ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, | 187 | ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, |
170 | ast::SourceFile(_it) => ImmediateLocation::ItemList, | 188 | ast::SourceFile(_it) => ImmediateLocation::ItemList, |
171 | ast::ItemList(_it) => ImmediateLocation::ItemList, | 189 | ast::ItemList(_it) => ImmediateLocation::ItemList, |
172 | ast::RefExpr(_it) => ImmediateLocation::RefExpr, | 190 | ast::RefExpr(_it) => ImmediateLocation::RefExpr, |
173 | ast::RecordField(_it) => ImmediateLocation::RecordField, | 191 | ast::RecordField(it) => if it.ty().map_or(false, |it| it.syntax().text_range().contains(offset)) { |
192 | return None; | ||
193 | } else { | ||
194 | ImmediateLocation::RecordField | ||
195 | }, | ||
196 | ast::TupleField(_it) => ImmediateLocation::TupleField, | ||
197 | ast::TupleFieldList(_it) => ImmediateLocation::TupleField, | ||
174 | ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) { | 198 | ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) { |
175 | Some(IMPL) => ImmediateLocation::Impl, | 199 | Some(IMPL) => ImmediateLocation::Impl, |
176 | Some(TRAIT) => ImmediateLocation::Trait, | 200 | Some(TRAIT) => ImmediateLocation::Trait, |
@@ -310,7 +334,7 @@ fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> { | |||
310 | mod tests { | 334 | mod tests { |
311 | use syntax::algo::find_node_at_offset; | 335 | use syntax::algo::find_node_at_offset; |
312 | 336 | ||
313 | use crate::test_utils::position; | 337 | use crate::tests::position; |
314 | 338 | ||
315 | use super::*; | 339 | use super::*; |
316 | 340 | ||
@@ -359,8 +383,8 @@ mod tests { | |||
359 | fn test_use_loc() { | 383 | fn test_use_loc() { |
360 | check_location(r"use f$0", ImmediateLocation::Use); | 384 | check_location(r"use f$0", ImmediateLocation::Use); |
361 | check_location(r"use f$0;", ImmediateLocation::Use); | 385 | check_location(r"use f$0;", ImmediateLocation::Use); |
362 | check_location(r"use f::{f$0}", None); | 386 | check_location(r"use f::{f$0}", ImmediateLocation::UseTree); |
363 | check_location(r"use {f$0}", None); | 387 | check_location(r"use {f$0}", ImmediateLocation::UseTree); |
364 | } | 388 | } |
365 | 389 | ||
366 | #[test] | 390 | #[test] |
@@ -421,4 +445,14 @@ mod tests { | |||
421 | check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr); | 445 | check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr); |
422 | check_prev_sibling(r"fn foo() { if true {}; w$0", None); | 446 | check_prev_sibling(r"fn foo() { if true {}; w$0", None); |
423 | } | 447 | } |
448 | |||
449 | #[test] | ||
450 | fn test_vis_prev_sibling() { | ||
451 | check_prev_sibling(r"pub w$0", ImmediatePrevSibling::Visibility); | ||
452 | } | ||
453 | |||
454 | #[test] | ||
455 | fn test_attr_prev_sibling() { | ||
456 | check_prev_sibling(r"#[attr] w$0", ImmediatePrevSibling::Attribute); | ||
457 | } | ||
424 | } | 458 | } |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index d8ca18c73..1a9b6212a 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -23,53 +23,6 @@ use crate::{ | |||
23 | render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, | 23 | render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, |
24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, | 24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, |
25 | }; | 25 | }; |
26 | |||
27 | pub(crate) fn render_field( | ||
28 | ctx: RenderContext<'_>, | ||
29 | receiver: Option<hir::Name>, | ||
30 | field: hir::Field, | ||
31 | ty: &hir::Type, | ||
32 | ) -> CompletionItem { | ||
33 | render_field_(ctx, receiver, field, ty) | ||
34 | } | ||
35 | |||
36 | pub(crate) fn render_tuple_field( | ||
37 | ctx: RenderContext<'_>, | ||
38 | receiver: Option<hir::Name>, | ||
39 | field: usize, | ||
40 | ty: &hir::Type, | ||
41 | ) -> CompletionItem { | ||
42 | render_tuple_field_(ctx, receiver, field, ty) | ||
43 | } | ||
44 | |||
45 | pub(crate) fn render_resolution( | ||
46 | ctx: RenderContext<'_>, | ||
47 | local_name: hir::Name, | ||
48 | resolution: &hir::ScopeDef, | ||
49 | ) -> Option<CompletionItem> { | ||
50 | render_resolution_(ctx, local_name, None, resolution) | ||
51 | } | ||
52 | |||
53 | pub(crate) fn render_resolution_with_import( | ||
54 | ctx: RenderContext<'_>, | ||
55 | import_edit: ImportEdit, | ||
56 | ) -> Option<CompletionItem> { | ||
57 | let resolution = hir::ScopeDef::from(import_edit.import.original_item); | ||
58 | if ctx.completion.expects_type() && resolution.is_value_def() { | ||
59 | return None; | ||
60 | } | ||
61 | let local_name = match resolution { | ||
62 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), | ||
63 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, | ||
64 | hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), | ||
65 | _ => item_name(ctx.db(), import_edit.import.original_item)?, | ||
66 | }; | ||
67 | render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| { | ||
68 | item.completion_kind = CompletionKind::Magic; | ||
69 | item | ||
70 | }) | ||
71 | } | ||
72 | |||
73 | /// Interface for data and methods required for items rendering. | 26 | /// Interface for data and methods required for items rendering. |
74 | #[derive(Debug)] | 27 | #[derive(Debug)] |
75 | pub(crate) struct RenderContext<'a> { | 28 | pub(crate) struct RenderContext<'a> { |
@@ -122,7 +75,7 @@ impl<'a> RenderContext<'a> { | |||
122 | } | 75 | } |
123 | } | 76 | } |
124 | 77 | ||
125 | fn render_field_( | 78 | pub(crate) fn render_field( |
126 | ctx: RenderContext<'_>, | 79 | ctx: RenderContext<'_>, |
127 | receiver: Option<hir::Name>, | 80 | receiver: Option<hir::Name>, |
128 | field: hir::Field, | 81 | field: hir::Field, |
@@ -135,7 +88,6 @@ fn render_field_( | |||
135 | ctx.source_range(), | 88 | ctx.source_range(), |
136 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), | 89 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), |
137 | ); | 90 | ); |
138 | |||
139 | item.set_relevance(CompletionRelevance { | 91 | item.set_relevance(CompletionRelevance { |
140 | type_match: compute_type_match(ctx.completion, ty), | 92 | type_match: compute_type_match(ctx.completion, ty), |
141 | exact_name_match: compute_exact_name_match(ctx.completion, &name), | 93 | exact_name_match: compute_exact_name_match(ctx.completion, &name), |
@@ -146,17 +98,15 @@ fn render_field_( | |||
146 | .set_documentation(field.docs(ctx.db())) | 98 | .set_documentation(field.docs(ctx.db())) |
147 | .set_deprecated(is_deprecated) | 99 | .set_deprecated(is_deprecated) |
148 | .lookup_by(name); | 100 | .lookup_by(name); |
149 | |||
150 | if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { | 101 | if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { |
151 | // FIXME | 102 | // FIXME |
152 | // For now we don't properly calculate the edits for ref match | 103 | // For now we don't properly calculate the edits for ref match |
153 | // completions on struct fields, so we've disabled them. See #8058. | 104 | // completions on struct fields, so we've disabled them. See #8058. |
154 | } | 105 | } |
155 | |||
156 | item.build() | 106 | item.build() |
157 | } | 107 | } |
158 | 108 | ||
159 | fn render_tuple_field_( | 109 | pub(crate) fn render_tuple_field( |
160 | ctx: RenderContext<'_>, | 110 | ctx: RenderContext<'_>, |
161 | receiver: Option<hir::Name>, | 111 | receiver: Option<hir::Name>, |
162 | field: usize, | 112 | field: usize, |
@@ -167,14 +117,37 @@ fn render_tuple_field_( | |||
167 | ctx.source_range(), | 117 | ctx.source_range(), |
168 | receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), | 118 | receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), |
169 | ); | 119 | ); |
170 | |||
171 | item.kind(SymbolKind::Field) | 120 | item.kind(SymbolKind::Field) |
172 | .detail(ty.display(ctx.db()).to_string()) | 121 | .detail(ty.display(ctx.db()).to_string()) |
173 | .lookup_by(field.to_string()); | 122 | .lookup_by(field.to_string()); |
174 | |||
175 | item.build() | 123 | item.build() |
176 | } | 124 | } |
177 | 125 | ||
126 | pub(crate) fn render_resolution( | ||
127 | ctx: RenderContext<'_>, | ||
128 | local_name: hir::Name, | ||
129 | resolution: &hir::ScopeDef, | ||
130 | ) -> Option<CompletionItem> { | ||
131 | render_resolution_(ctx, local_name, None, resolution) | ||
132 | } | ||
133 | |||
134 | pub(crate) fn render_resolution_with_import( | ||
135 | ctx: RenderContext<'_>, | ||
136 | import_edit: ImportEdit, | ||
137 | ) -> Option<CompletionItem> { | ||
138 | let resolution = hir::ScopeDef::from(import_edit.import.original_item); | ||
139 | let local_name = match resolution { | ||
140 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), | ||
141 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, | ||
142 | hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), | ||
143 | _ => item_name(ctx.db(), import_edit.import.original_item)?, | ||
144 | }; | ||
145 | render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| { | ||
146 | item.completion_kind = CompletionKind::Magic; | ||
147 | item | ||
148 | }) | ||
149 | } | ||
150 | |||
178 | fn render_resolution_( | 151 | fn render_resolution_( |
179 | ctx: RenderContext<'_>, | 152 | ctx: RenderContext<'_>, |
180 | local_name: hir::Name, | 153 | local_name: hir::Name, |
@@ -362,7 +335,7 @@ mod tests { | |||
362 | 335 | ||
363 | use crate::{ | 336 | use crate::{ |
364 | item::CompletionRelevanceTypeMatch, | 337 | item::CompletionRelevanceTypeMatch, |
365 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, | 338 | tests::{check_edit, do_completion, get_all_items, TEST_CONFIG}, |
366 | CompletionKind, CompletionRelevance, | 339 | CompletionKind, CompletionRelevance, |
367 | }; | 340 | }; |
368 | 341 | ||
@@ -1084,7 +1057,7 @@ fn f() { | |||
1084 | #[test] | 1057 | #[test] |
1085 | fn suggest_ref_mut() { | 1058 | fn suggest_ref_mut() { |
1086 | cov_mark::check!(suggest_ref); | 1059 | cov_mark::check!(suggest_ref); |
1087 | check( | 1060 | check_relevance( |
1088 | r#" | 1061 | r#" |
1089 | struct S; | 1062 | struct S; |
1090 | fn foo(s: &mut S) {} | 1063 | fn foo(s: &mut S) {} |
@@ -1094,74 +1067,40 @@ fn main() { | |||
1094 | } | 1067 | } |
1095 | "#, | 1068 | "#, |
1096 | expect![[r#" | 1069 | expect![[r#" |
1097 | [ | 1070 | lc s [name+local] |
1098 | CompletionItem { | 1071 | lc &mut s [type+name+local] |
1099 | label: "S", | 1072 | st S [] |
1100 | source_range: 70..70, | 1073 | fn main() [] |
1101 | delete: 70..70, | 1074 | fn foo(…) [] |
1102 | insert: "S", | ||
1103 | kind: SymbolKind( | ||
1104 | Struct, | ||
1105 | ), | ||
1106 | }, | ||
1107 | CompletionItem { | ||
1108 | label: "foo(…)", | ||
1109 | source_range: 70..70, | ||
1110 | delete: 70..70, | ||
1111 | insert: "foo(${1:&mut s})$0", | ||
1112 | kind: SymbolKind( | ||
1113 | Function, | ||
1114 | ), | ||
1115 | lookup: "foo", | ||
1116 | detail: "fn(&mut S)", | ||
1117 | trigger_call_info: true, | ||
1118 | }, | ||
1119 | CompletionItem { | ||
1120 | label: "main()", | ||
1121 | source_range: 70..70, | ||
1122 | delete: 70..70, | ||
1123 | insert: "main()$0", | ||
1124 | kind: SymbolKind( | ||
1125 | Function, | ||
1126 | ), | ||
1127 | lookup: "main", | ||
1128 | detail: "fn()", | ||
1129 | }, | ||
1130 | CompletionItem { | ||
1131 | label: "s", | ||
1132 | source_range: 70..70, | ||
1133 | delete: 70..70, | ||
1134 | insert: "s", | ||
1135 | kind: SymbolKind( | ||
1136 | Local, | ||
1137 | ), | ||
1138 | detail: "S", | ||
1139 | relevance: CompletionRelevance { | ||
1140 | exact_name_match: true, | ||
1141 | type_match: None, | ||
1142 | is_local: true, | ||
1143 | }, | ||
1144 | ref_match: "&mut ", | ||
1145 | }, | ||
1146 | ] | ||
1147 | "#]], | 1075 | "#]], |
1148 | ) | 1076 | ); |
1077 | check_relevance( | ||
1078 | r#" | ||
1079 | struct S; | ||
1080 | fn foo(s: &mut S) {} | ||
1081 | fn main() { | ||
1082 | let mut s = S; | ||
1083 | foo(&mut $0); | ||
1084 | } | ||
1085 | "#, | ||
1086 | expect![[r#" | ||
1087 | lc s [type+name+local] | ||
1088 | st S [] | ||
1089 | fn main() [] | ||
1090 | fn foo(…) [] | ||
1091 | "#]], | ||
1092 | ); | ||
1149 | } | 1093 | } |
1150 | 1094 | ||
1151 | #[test] | 1095 | #[test] |
1152 | fn suggest_deref() { | 1096 | fn suggest_deref() { |
1153 | check_relevance( | 1097 | check_relevance( |
1154 | r#" | 1098 | r#" |
1155 | #[lang = "deref"] | 1099 | //- minicore: deref |
1156 | trait Deref { | ||
1157 | type Target; | ||
1158 | fn deref(&self) -> &Self::Target; | ||
1159 | } | ||
1160 | |||
1161 | struct S; | 1100 | struct S; |
1162 | struct T(S); | 1101 | struct T(S); |
1163 | 1102 | ||
1164 | impl Deref for T { | 1103 | impl core::ops::Deref for T { |
1165 | type Target = S; | 1104 | type Target = S; |
1166 | 1105 | ||
1167 | fn deref(&self) -> &Self::Target { | 1106 | fn deref(&self) -> &Self::Target { |
@@ -1185,8 +1124,9 @@ fn main() { | |||
1185 | st T [] | 1124 | st T [] |
1186 | st S [] | 1125 | st S [] |
1187 | fn main() [] | 1126 | fn main() [] |
1188 | tt Deref [] | ||
1189 | fn foo(…) [] | 1127 | fn foo(…) [] |
1128 | md core [] | ||
1129 | tt Sized [] | ||
1190 | "#]], | 1130 | "#]], |
1191 | ) | 1131 | ) |
1192 | } | 1132 | } |
@@ -1195,21 +1135,11 @@ fn main() { | |||
1195 | fn suggest_deref_mut() { | 1135 | fn suggest_deref_mut() { |
1196 | check_relevance( | 1136 | check_relevance( |
1197 | r#" | 1137 | r#" |
1198 | #[lang = "deref"] | 1138 | //- minicore: deref_mut |
1199 | trait Deref { | ||
1200 | type Target; | ||
1201 | fn deref(&self) -> &Self::Target; | ||
1202 | } | ||
1203 | |||
1204 | #[lang = "deref_mut"] | ||
1205 | pub trait DerefMut: Deref { | ||
1206 | fn deref_mut(&mut self) -> &mut Self::Target; | ||
1207 | } | ||
1208 | |||
1209 | struct S; | 1139 | struct S; |
1210 | struct T(S); | 1140 | struct T(S); |
1211 | 1141 | ||
1212 | impl Deref for T { | 1142 | impl core::ops::Deref for T { |
1213 | type Target = S; | 1143 | type Target = S; |
1214 | 1144 | ||
1215 | fn deref(&self) -> &Self::Target { | 1145 | fn deref(&self) -> &Self::Target { |
@@ -1217,7 +1147,7 @@ impl Deref for T { | |||
1217 | } | 1147 | } |
1218 | } | 1148 | } |
1219 | 1149 | ||
1220 | impl DerefMut for T { | 1150 | impl core::ops::DerefMut for T { |
1221 | fn deref_mut(&mut self) -> &mut Self::Target { | 1151 | fn deref_mut(&mut self) -> &mut Self::Target { |
1222 | &mut self.0 | 1152 | &mut self.0 |
1223 | } | 1153 | } |
@@ -1236,12 +1166,12 @@ fn main() { | |||
1236 | lc m [local] | 1166 | lc m [local] |
1237 | lc t [local] | 1167 | lc t [local] |
1238 | lc &mut t [type+local] | 1168 | lc &mut t [type+local] |
1239 | tt DerefMut [] | ||
1240 | tt Deref [] | ||
1241 | fn foo(…) [] | ||
1242 | st T [] | 1169 | st T [] |
1243 | st S [] | 1170 | st S [] |
1244 | fn main() [] | 1171 | fn main() [] |
1172 | fn foo(…) [] | ||
1173 | md core [] | ||
1174 | tt Sized [] | ||
1245 | "#]], | 1175 | "#]], |
1246 | ) | 1176 | ) |
1247 | } | 1177 | } |
@@ -1310,16 +1240,11 @@ fn bar(t: &Foo) {} | |||
1310 | fn suggest_deref_fn_ret() { | 1240 | fn suggest_deref_fn_ret() { |
1311 | check_relevance( | 1241 | check_relevance( |
1312 | r#" | 1242 | r#" |
1313 | #[lang = "deref"] | 1243 | //- minicore: deref |
1314 | trait Deref { | ||
1315 | type Target; | ||
1316 | fn deref(&self) -> &Self::Target; | ||
1317 | } | ||
1318 | |||
1319 | struct S; | 1244 | struct S; |
1320 | struct T(S); | 1245 | struct T(S); |
1321 | 1246 | ||
1322 | impl Deref for T { | 1247 | impl core::ops::Deref for T { |
1323 | type Target = S; | 1248 | type Target = S; |
1324 | 1249 | ||
1325 | fn deref(&self) -> &Self::Target { | 1250 | fn deref(&self) -> &Self::Target { |
@@ -1333,15 +1258,16 @@ fn bar() -> T {} | |||
1333 | fn main() { | 1258 | fn main() { |
1334 | foo($0); | 1259 | foo($0); |
1335 | } | 1260 | } |
1336 | "#, | 1261 | "#, |
1337 | expect![[r#" | 1262 | expect![[r#" |
1338 | tt Deref [] | ||
1339 | fn bar() [] | ||
1340 | fn &bar() [type] | ||
1341 | fn foo(…) [] | ||
1342 | st T [] | 1263 | st T [] |
1343 | st S [] | 1264 | st S [] |
1344 | fn main() [] | 1265 | fn main() [] |
1266 | fn bar() [] | ||
1267 | fn &bar() [type] | ||
1268 | fn foo(…) [] | ||
1269 | md core [] | ||
1270 | tt Sized [] | ||
1345 | "#]], | 1271 | "#]], |
1346 | ) | 1272 | ) |
1347 | } | 1273 | } |
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs index c54752d30..33d3a5ee1 100644 --- a/crates/ide_completion/src/render/builder_ext.rs +++ b/crates/ide_completion/src/render/builder_ext.rs | |||
@@ -28,11 +28,11 @@ impl Builder { | |||
28 | if !ctx.config.add_call_parenthesis { | 28 | if !ctx.config.add_call_parenthesis { |
29 | return false; | 29 | return false; |
30 | } | 30 | } |
31 | if ctx.use_item_syntax.is_some() { | 31 | if ctx.in_use_tree() { |
32 | cov_mark::hit!(no_parens_in_use_item); | 32 | cov_mark::hit!(no_parens_in_use_item); |
33 | return false; | 33 | return false; |
34 | } | 34 | } |
35 | if matches!(ctx.path_call_kind(), Some(CallKind::Expr) | Some(CallKind::Pat)) | 35 | if matches!(ctx.path_call_kind(), Some(CallKind::Expr | CallKind::Pat)) |
36 | | matches!( | 36 | | matches!( |
37 | ctx.completion_location, | 37 | ctx.completion_location, |
38 | Some(ImmediateLocation::MethodCall { has_parens: true, .. }) | 38 | Some(ImmediateLocation::MethodCall { has_parens: true, .. }) |
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs index 28f056e77..91dc178f3 100644 --- a/crates/ide_completion/src/render/enum_variant.rs +++ b/crates/ide_completion/src/render/enum_variant.rs | |||
@@ -121,7 +121,7 @@ impl<'a> EnumRender<'a> { | |||
121 | 121 | ||
122 | #[cfg(test)] | 122 | #[cfg(test)] |
123 | mod tests { | 123 | mod tests { |
124 | use crate::test_utils::check_edit; | 124 | use crate::tests::check_edit; |
125 | 125 | ||
126 | #[test] | 126 | #[test] |
127 | fn inserts_parens_for_tuple_enums() { | 127 | fn inserts_parens_for_tuple_enums() { |
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index 1357b9f4a..19f2c86e9 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs | |||
@@ -191,7 +191,7 @@ impl<'a> FunctionRender<'a> { | |||
191 | #[cfg(test)] | 191 | #[cfg(test)] |
192 | mod tests { | 192 | mod tests { |
193 | use crate::{ | 193 | use crate::{ |
194 | test_utils::{check_edit, check_edit_with_config, TEST_CONFIG}, | 194 | tests::{check_edit, check_edit_with_config, TEST_CONFIG}, |
195 | CompletionConfig, | 195 | CompletionConfig, |
196 | }; | 196 | }; |
197 | 197 | ||
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs index 429d937c8..4d5179c4f 100644 --- a/crates/ide_completion/src/render/macro_.rs +++ b/crates/ide_completion/src/render/macro_.rs | |||
@@ -69,7 +69,7 @@ impl<'a> MacroRender<'a> { | |||
69 | } | 69 | } |
70 | 70 | ||
71 | fn needs_bang(&self) -> bool { | 71 | fn needs_bang(&self) -> bool { |
72 | self.ctx.completion.use_item_syntax.is_none() | 72 | !self.ctx.completion.in_use_tree() |
73 | && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) | 73 | && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) |
74 | } | 74 | } |
75 | 75 | ||
@@ -133,7 +133,7 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s | |||
133 | 133 | ||
134 | #[cfg(test)] | 134 | #[cfg(test)] |
135 | mod tests { | 135 | mod tests { |
136 | use crate::test_utils::check_edit; | 136 | use crate::tests::check_edit; |
137 | 137 | ||
138 | #[test] | 138 | #[test] |
139 | fn dont_insert_macro_call_parens_unncessary() { | 139 | fn dont_insert_macro_call_parens_unncessary() { |
@@ -180,7 +180,7 @@ fn main() { frobnicate!(); } | |||
180 | /// ``` | 180 | /// ``` |
181 | macro_rules! vec { () => {} } | 181 | macro_rules! vec { () => {} } |
182 | 182 | ||
183 | fn fn main() { v$0 } | 183 | fn main() { v$0 } |
184 | "#, | 184 | "#, |
185 | r#" | 185 | r#" |
186 | /// Creates a [`Vec`] containing the arguments. | 186 | /// Creates a [`Vec`] containing the arguments. |
@@ -193,7 +193,7 @@ fn fn main() { v$0 } | |||
193 | /// ``` | 193 | /// ``` |
194 | macro_rules! vec { () => {} } | 194 | macro_rules! vec { () => {} } |
195 | 195 | ||
196 | fn fn main() { vec![$0] } | 196 | fn main() { vec![$0] } |
197 | "#, | 197 | "#, |
198 | ); | 198 | ); |
199 | 199 | ||
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/tests.rs index b0a4b2026..97298ff27 100644 --- a/crates/ide_completion/src/test_utils.rs +++ b/crates/ide_completion/src/tests.rs | |||
@@ -1,4 +1,16 @@ | |||
1 | //! Runs completion for testing purposes. | 1 | //! Tests and test utilities for completions. |
2 | //! | ||
3 | //! Most tests live in this module or its submodules unless for very specific completions like | ||
4 | //! `attributes` or `lifetimes` where the completed concept is a distinct thing. | ||
5 | //! Notable examples for completions that are being tested in this module's submodule are paths. | ||
6 | |||
7 | mod item_list; | ||
8 | mod use_tree; | ||
9 | mod items; | ||
10 | mod pattern; | ||
11 | mod type_pos; | ||
12 | |||
13 | use std::mem; | ||
2 | 14 | ||
3 | use hir::{PrefixKind, Semantics}; | 15 | use hir::{PrefixKind, Semantics}; |
4 | use ide_db::{ | 16 | use ide_db::{ |
@@ -28,9 +40,27 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { | |||
28 | prefix_kind: PrefixKind::Plain, | 40 | prefix_kind: PrefixKind::Plain, |
29 | enforce_granularity: true, | 41 | enforce_granularity: true, |
30 | group: true, | 42 | group: true, |
43 | skip_glob_imports: true, | ||
31 | }, | 44 | }, |
32 | }; | 45 | }; |
33 | 46 | ||
47 | pub(crate) fn completion_list(code: &str) -> String { | ||
48 | completion_list_with_config(TEST_CONFIG, code) | ||
49 | } | ||
50 | |||
51 | fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { | ||
52 | // filter out all but one builtintype completion for smaller test outputs | ||
53 | let items = get_all_items(config, code); | ||
54 | let mut bt_seen = false; | ||
55 | let items = items | ||
56 | .into_iter() | ||
57 | .filter(|it| { | ||
58 | it.completion_kind != CompletionKind::BuiltinType || !mem::replace(&mut bt_seen, true) | ||
59 | }) | ||
60 | .collect(); | ||
61 | render_completion_list(items) | ||
62 | } | ||
63 | |||
34 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | 64 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
35 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | 65 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { |
36 | let change_fixture = ChangeFixture::parse(ra_fixture); | 66 | let change_fixture = ChangeFixture::parse(ra_fixture); |
@@ -57,24 +87,27 @@ pub(crate) fn do_completion_with_config( | |||
57 | .collect() | 87 | .collect() |
58 | } | 88 | } |
59 | 89 | ||
60 | pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { | 90 | pub(crate) fn filtered_completion_list(code: &str, kind: CompletionKind) -> String { |
61 | completion_list_with_config(TEST_CONFIG, code, kind) | 91 | filtered_completion_list_with_config(TEST_CONFIG, code, kind) |
62 | } | 92 | } |
63 | 93 | ||
64 | pub(crate) fn completion_list_with_config( | 94 | pub(crate) fn filtered_completion_list_with_config( |
65 | config: CompletionConfig, | 95 | config: CompletionConfig, |
66 | code: &str, | 96 | code: &str, |
67 | kind: CompletionKind, | 97 | kind: CompletionKind, |
68 | ) -> String { | 98 | ) -> String { |
69 | let kind_completions: Vec<CompletionItem> = | 99 | let kind_completions: Vec<CompletionItem> = |
70 | get_all_items(config, code).into_iter().filter(|c| c.completion_kind == kind).collect(); | 100 | get_all_items(config, code).into_iter().filter(|c| c.completion_kind == kind).collect(); |
71 | let label_width = kind_completions | 101 | render_completion_list(kind_completions) |
72 | .iter() | 102 | } |
73 | .map(|it| monospace_width(it.label())) | 103 | |
74 | .max() | 104 | fn render_completion_list(completions: Vec<CompletionItem>) -> String { |
75 | .unwrap_or_default() | 105 | fn monospace_width(s: &str) -> usize { |
76 | .min(16); | 106 | s.chars().count() |
77 | kind_completions | 107 | } |
108 | let label_width = | ||
109 | completions.iter().map(|it| monospace_width(it.label())).max().unwrap_or_default().min(16); | ||
110 | completions | ||
78 | .into_iter() | 111 | .into_iter() |
79 | .map(|it| { | 112 | .map(|it| { |
80 | let tag = it.kind().unwrap().tag(); | 113 | let tag = it.kind().unwrap().tag(); |
@@ -93,10 +126,6 @@ pub(crate) fn completion_list_with_config( | |||
93 | .collect() | 126 | .collect() |
94 | } | 127 | } |
95 | 128 | ||
96 | fn monospace_width(s: &str) -> usize { | ||
97 | s.chars().count() | ||
98 | } | ||
99 | |||
100 | pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 129 | pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
101 | check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after) | 130 | check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after) |
102 | } | 131 | } |
@@ -152,3 +181,18 @@ pub(crate) fn get_all_items(config: CompletionConfig, code: &str) -> Vec<Complet | |||
152 | let (db, position) = position(code); | 181 | let (db, position) = position(code); |
153 | crate::completions(&db, &config, position).unwrap().into() | 182 | crate::completions(&db, &config, position).unwrap().into() |
154 | } | 183 | } |
184 | |||
185 | fn check_no_completion(ra_fixture: &str) { | ||
186 | let (db, position) = position(ra_fixture); | ||
187 | |||
188 | assert!( | ||
189 | crate::completions(&db, &TEST_CONFIG, position).is_none(), | ||
190 | "Completions were generated, but weren't expected" | ||
191 | ); | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn test_no_completions_required() { | ||
196 | cov_mark::check!(no_completion_required); | ||
197 | check_no_completion(r#"fn foo() { for i i$0 }"#); | ||
198 | } | ||
diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs new file mode 100644 index 000000000..7c124ac37 --- /dev/null +++ b/crates/ide_completion/src/tests/item_list.rs | |||
@@ -0,0 +1,223 @@ | |||
1 | use expect_test::{expect, Expect}; | ||
2 | |||
3 | use crate::tests::completion_list; | ||
4 | |||
5 | fn check(ra_fixture: &str, expect: Expect) { | ||
6 | let base = r#"#[rustc_builtin_macro] | ||
7 | pub macro Clone {} | ||
8 | enum Enum { Variant } | ||
9 | struct Struct {} | ||
10 | #[macro_export] | ||
11 | macro_rules! foo {} | ||
12 | mod bar {} | ||
13 | const CONST: () = (); | ||
14 | trait Trait {} | ||
15 | "#; | ||
16 | let actual = completion_list(&format!("{}{}", base, ra_fixture)); | ||
17 | expect.assert_eq(&actual) | ||
18 | } | ||
19 | |||
20 | #[test] | ||
21 | fn in_mod_item_list() { | ||
22 | check( | ||
23 | r#"mod tests { $0 }"#, | ||
24 | expect![[r##" | ||
25 | kw pub(crate) | ||
26 | kw pub | ||
27 | kw unsafe | ||
28 | kw fn | ||
29 | kw const | ||
30 | kw type | ||
31 | kw impl | ||
32 | kw extern | ||
33 | kw use | ||
34 | kw trait | ||
35 | kw static | ||
36 | kw mod | ||
37 | kw enum | ||
38 | kw struct | ||
39 | kw union | ||
40 | sn tmod (Test module) | ||
41 | sn tfn (Test function) | ||
42 | sn macro_rules | ||
43 | ma foo!(…) #[macro_export] macro_rules! foo | ||
44 | "##]], | ||
45 | ) | ||
46 | } | ||
47 | |||
48 | #[test] | ||
49 | fn in_source_file_item_list() { | ||
50 | check( | ||
51 | r#"$0"#, | ||
52 | expect![[r##" | ||
53 | kw pub(crate) | ||
54 | kw pub | ||
55 | kw unsafe | ||
56 | kw fn | ||
57 | kw const | ||
58 | kw type | ||
59 | kw impl | ||
60 | kw extern | ||
61 | kw use | ||
62 | kw trait | ||
63 | kw static | ||
64 | kw mod | ||
65 | kw enum | ||
66 | kw struct | ||
67 | kw union | ||
68 | sn tmod (Test module) | ||
69 | sn tfn (Test function) | ||
70 | sn macro_rules | ||
71 | md bar | ||
72 | ma foo!(…) #[macro_export] macro_rules! foo | ||
73 | ma foo!(…) #[macro_export] macro_rules! foo | ||
74 | "##]], | ||
75 | ) | ||
76 | } | ||
77 | |||
78 | #[test] | ||
79 | fn in_item_list_after_attr() { | ||
80 | check( | ||
81 | r#"#[attr] $0"#, | ||
82 | expect![[r#" | ||
83 | kw pub(crate) | ||
84 | kw pub | ||
85 | kw unsafe | ||
86 | kw fn | ||
87 | kw const | ||
88 | kw type | ||
89 | kw impl | ||
90 | kw extern | ||
91 | kw use | ||
92 | kw trait | ||
93 | kw static | ||
94 | kw mod | ||
95 | kw enum | ||
96 | kw struct | ||
97 | kw union | ||
98 | sn tmod (Test module) | ||
99 | sn tfn (Test function) | ||
100 | sn macro_rules | ||
101 | "#]], | ||
102 | ) | ||
103 | } | ||
104 | |||
105 | #[test] | ||
106 | fn in_qualified_path() { | ||
107 | check( | ||
108 | r#"crate::$0"#, | ||
109 | expect![[r##" | ||
110 | kw pub(crate) | ||
111 | kw pub | ||
112 | kw unsafe | ||
113 | kw fn | ||
114 | kw const | ||
115 | kw type | ||
116 | kw impl | ||
117 | kw extern | ||
118 | kw use | ||
119 | kw trait | ||
120 | kw static | ||
121 | kw mod | ||
122 | kw enum | ||
123 | kw struct | ||
124 | kw union | ||
125 | md bar | ||
126 | ma foo!(…) #[macro_export] macro_rules! foo | ||
127 | "##]], | ||
128 | ) | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn after_unsafe_token() { | ||
133 | check( | ||
134 | r#"unsafe $0"#, | ||
135 | expect![[r#" | ||
136 | kw fn | ||
137 | kw trait | ||
138 | kw impl | ||
139 | "#]], | ||
140 | ); | ||
141 | } | ||
142 | |||
143 | #[test] | ||
144 | fn after_visibility() { | ||
145 | check( | ||
146 | r#"pub $0"#, | ||
147 | expect![[r#" | ||
148 | kw unsafe | ||
149 | kw fn | ||
150 | kw const | ||
151 | kw type | ||
152 | kw use | ||
153 | kw trait | ||
154 | kw static | ||
155 | kw mod | ||
156 | kw enum | ||
157 | kw struct | ||
158 | kw union | ||
159 | "#]], | ||
160 | ); | ||
161 | } | ||
162 | |||
163 | #[test] | ||
164 | fn after_visibility_unsafe() { | ||
165 | // FIXME this shouldn't show `impl` | ||
166 | check( | ||
167 | r#"pub unsafe $0"#, | ||
168 | expect![[r#" | ||
169 | kw fn | ||
170 | kw trait | ||
171 | kw impl | ||
172 | "#]], | ||
173 | ); | ||
174 | } | ||
175 | |||
176 | #[test] | ||
177 | fn in_impl_assoc_item_list() { | ||
178 | check( | ||
179 | r#"impl Struct { $0 }"#, | ||
180 | expect![[r##" | ||
181 | kw pub(crate) | ||
182 | kw pub | ||
183 | kw unsafe | ||
184 | kw fn | ||
185 | kw const | ||
186 | kw type | ||
187 | md bar | ||
188 | ma foo!(…) #[macro_export] macro_rules! foo | ||
189 | ma foo!(…) #[macro_export] macro_rules! foo | ||
190 | "##]], | ||
191 | ) | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn in_impl_assoc_item_list_after_attr() { | ||
196 | check( | ||
197 | r#"impl Struct { #[attr] $0 }"#, | ||
198 | expect![[r#" | ||
199 | kw pub(crate) | ||
200 | kw pub | ||
201 | kw unsafe | ||
202 | kw fn | ||
203 | kw const | ||
204 | kw type | ||
205 | "#]], | ||
206 | ) | ||
207 | } | ||
208 | |||
209 | #[test] | ||
210 | fn in_trait_assoc_item_list() { | ||
211 | check( | ||
212 | r"trait Foo { $0 }", | ||
213 | expect![[r##" | ||
214 | kw unsafe | ||
215 | kw fn | ||
216 | kw const | ||
217 | kw type | ||
218 | md bar | ||
219 | ma foo!(…) #[macro_export] macro_rules! foo | ||
220 | ma foo!(…) #[macro_export] macro_rules! foo | ||
221 | "##]], | ||
222 | ); | ||
223 | } | ||
diff --git a/crates/ide_completion/src/tests/items.rs b/crates/ide_completion/src/tests/items.rs new file mode 100644 index 000000000..b98baffd6 --- /dev/null +++ b/crates/ide_completion/src/tests/items.rs | |||
@@ -0,0 +1,95 @@ | |||
1 | //! Completions tests for item specifics overall. | ||
2 | //! | ||
3 | //! Except for use items which are tested in [super::use_tree] and mod declarations with are tested | ||
4 | //! in [crate::completions::mod_]. | ||
5 | use expect_test::{expect, Expect}; | ||
6 | |||
7 | use crate::tests::completion_list; | ||
8 | |||
9 | fn check(ra_fixture: &str, expect: Expect) { | ||
10 | let base = r#"#[rustc_builtin_macro] | ||
11 | pub macro Clone {} | ||
12 | enum Enum { Variant } | ||
13 | struct Struct {} | ||
14 | #[macro_export] | ||
15 | macro_rules! foo {} | ||
16 | mod bar {} | ||
17 | const CONST: () = (); | ||
18 | trait Trait {} | ||
19 | "#; | ||
20 | let actual = completion_list(&format!("{}{}", base, ra_fixture)); | ||
21 | expect.assert_eq(&actual) | ||
22 | } | ||
23 | |||
24 | #[test] | ||
25 | fn target_type_or_trait_in_impl_block() { | ||
26 | check( | ||
27 | r#" | ||
28 | impl Tra$0 | ||
29 | "#, | ||
30 | expect![[r##" | ||
31 | tt Trait | ||
32 | en Enum | ||
33 | st Struct | ||
34 | md bar | ||
35 | ma foo!(…) #[macro_export] macro_rules! foo | ||
36 | ma foo!(…) #[macro_export] macro_rules! foo | ||
37 | bt u32 | ||
38 | "##]], | ||
39 | ) | ||
40 | } | ||
41 | |||
42 | #[test] | ||
43 | fn target_type_in_trait_impl_block() { | ||
44 | check( | ||
45 | r#" | ||
46 | impl Trait for Str$0 | ||
47 | "#, | ||
48 | expect![[r##" | ||
49 | tt Trait | ||
50 | en Enum | ||
51 | st Struct | ||
52 | md bar | ||
53 | ma foo!(…) #[macro_export] macro_rules! foo | ||
54 | ma foo!(…) #[macro_export] macro_rules! foo | ||
55 | bt u32 | ||
56 | "##]], | ||
57 | ) | ||
58 | } | ||
59 | |||
60 | #[test] | ||
61 | fn after_trait_name_in_trait_def() { | ||
62 | check( | ||
63 | r"trait A $0", | ||
64 | expect![[r#" | ||
65 | kw where | ||
66 | "#]], | ||
67 | ); | ||
68 | } | ||
69 | |||
70 | #[test] | ||
71 | fn after_trait_or_target_name_in_impl() { | ||
72 | check( | ||
73 | r"impl Trait $0", | ||
74 | expect![[r#" | ||
75 | kw where | ||
76 | kw for | ||
77 | "#]], | ||
78 | ); | ||
79 | } | ||
80 | |||
81 | #[test] | ||
82 | fn before_record_field() { | ||
83 | check( | ||
84 | r#" | ||
85 | struct Foo { | ||
86 | $0 | ||
87 | pub f: i32, | ||
88 | } | ||
89 | "#, | ||
90 | expect![[r#" | ||
91 | kw pub(crate) | ||
92 | kw pub | ||
93 | "#]], | ||
94 | ) | ||
95 | } | ||
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs new file mode 100644 index 000000000..1ad5ccd97 --- /dev/null +++ b/crates/ide_completion/src/tests/pattern.rs | |||
@@ -0,0 +1,348 @@ | |||
1 | //! Completions tests for pattern position. | ||
2 | use expect_test::{expect, Expect}; | ||
3 | |||
4 | use crate::tests::completion_list; | ||
5 | |||
6 | fn check(ra_fixture: &str, expect: Expect) { | ||
7 | let actual = completion_list(ra_fixture); | ||
8 | expect.assert_eq(&actual) | ||
9 | } | ||
10 | |||
11 | fn check_with(ra_fixture: &str, expect: Expect) { | ||
12 | let base = r#" | ||
13 | enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV } | ||
14 | use self::Enum::TupleV; | ||
15 | mod module {} | ||
16 | |||
17 | static STATIC: Unit = Unit; | ||
18 | const CONST: Unit = Unit; | ||
19 | struct Record { field: u32 } | ||
20 | struct Tuple(u32); | ||
21 | struct Unit | ||
22 | macro_rules! makro {} | ||
23 | "#; | ||
24 | let actual = completion_list(&format!("{}\n{}", base, ra_fixture)); | ||
25 | expect.assert_eq(&actual) | ||
26 | } | ||
27 | |||
28 | #[test] | ||
29 | fn ident_rebind_pat() { | ||
30 | check( | ||
31 | r#" | ||
32 | fn quux() { | ||
33 | let en$0 @ x | ||
34 | } | ||
35 | "#, | ||
36 | expect![[r#" | ||
37 | kw mut | ||
38 | "#]], | ||
39 | ); | ||
40 | } | ||
41 | |||
42 | #[test] | ||
43 | fn ident_ref_pat() { | ||
44 | check( | ||
45 | r#" | ||
46 | fn quux() { | ||
47 | let ref en$0 | ||
48 | } | ||
49 | "#, | ||
50 | expect![[r#" | ||
51 | kw mut | ||
52 | "#]], | ||
53 | ); | ||
54 | check( | ||
55 | r#" | ||
56 | fn quux() { | ||
57 | let ref en$0 @ x | ||
58 | } | ||
59 | "#, | ||
60 | expect![[r#" | ||
61 | kw mut | ||
62 | "#]], | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | #[test] | ||
67 | fn ident_ref_mut_pat() { | ||
68 | // FIXME mut is already here, don't complete it again | ||
69 | check( | ||
70 | r#" | ||
71 | fn quux() { | ||
72 | let ref mut en$0 | ||
73 | } | ||
74 | "#, | ||
75 | expect![[r#" | ||
76 | kw mut | ||
77 | "#]], | ||
78 | ); | ||
79 | check( | ||
80 | r#" | ||
81 | fn quux() { | ||
82 | let ref mut en$0 @ x | ||
83 | } | ||
84 | "#, | ||
85 | expect![[r#" | ||
86 | kw mut | ||
87 | "#]], | ||
88 | ); | ||
89 | } | ||
90 | |||
91 | #[test] | ||
92 | fn ref_pat() { | ||
93 | check( | ||
94 | r#" | ||
95 | fn quux() { | ||
96 | let &en$0 | ||
97 | } | ||
98 | "#, | ||
99 | expect![[r#" | ||
100 | kw mut | ||
101 | "#]], | ||
102 | ); | ||
103 | // FIXME mut is already here, don't complete it again | ||
104 | check( | ||
105 | r#" | ||
106 | fn quux() { | ||
107 | let &mut en$0 | ||
108 | } | ||
109 | "#, | ||
110 | expect![[r#" | ||
111 | kw mut | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn refutable() { | ||
118 | check_with( | ||
119 | r#" | ||
120 | fn foo() { | ||
121 | if let a$0 | ||
122 | } | ||
123 | "#, | ||
124 | expect![[r#" | ||
125 | kw mut | ||
126 | bn Record Record { field$1 }$0 | ||
127 | st Record | ||
128 | en Enum | ||
129 | bn Tuple Tuple($1)$0 | ||
130 | st Tuple | ||
131 | md module | ||
132 | bn TupleV TupleV($1)$0 | ||
133 | ev TupleV | ||
134 | st Unit | ||
135 | ct CONST | ||
136 | ma makro!(…) macro_rules! makro | ||
137 | "#]], | ||
138 | ); | ||
139 | } | ||
140 | |||
141 | #[test] | ||
142 | fn irrefutable() { | ||
143 | check_with( | ||
144 | r#" | ||
145 | fn foo() { | ||
146 | let a$0 | ||
147 | } | ||
148 | "#, | ||
149 | expect![[r#" | ||
150 | kw mut | ||
151 | bn Record Record { field$1 }$0 | ||
152 | st Record | ||
153 | bn Tuple Tuple($1)$0 | ||
154 | st Tuple | ||
155 | st Unit | ||
156 | ma makro!(…) macro_rules! makro | ||
157 | "#]], | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | #[test] | ||
162 | fn in_param() { | ||
163 | check_with( | ||
164 | r#" | ||
165 | fn foo(a$0) { | ||
166 | } | ||
167 | "#, | ||
168 | expect![[r#" | ||
169 | kw mut | ||
170 | bn Record Record { field$1 }: Record$0 | ||
171 | st Record | ||
172 | bn Tuple Tuple($1): Tuple$0 | ||
173 | st Tuple | ||
174 | st Unit | ||
175 | ma makro!(…) macro_rules! makro | ||
176 | "#]], | ||
177 | ); | ||
178 | } | ||
179 | |||
180 | #[test] | ||
181 | fn only_fn_like_macros() { | ||
182 | check( | ||
183 | r#" | ||
184 | macro_rules! m { ($e:expr) => { $e } } | ||
185 | |||
186 | #[rustc_builtin_macro] | ||
187 | macro Clone {} | ||
188 | |||
189 | fn foo() { | ||
190 | let x$0 | ||
191 | } | ||
192 | "#, | ||
193 | expect![[r#" | ||
194 | kw mut | ||
195 | ma m!(…) macro_rules! m | ||
196 | "#]], | ||
197 | ); | ||
198 | } | ||
199 | |||
200 | #[test] | ||
201 | fn in_simple_macro_call() { | ||
202 | check( | ||
203 | r#" | ||
204 | macro_rules! m { ($e:expr) => { $e } } | ||
205 | enum E { X } | ||
206 | |||
207 | fn foo() { | ||
208 | m!(match E::X { a$0 }) | ||
209 | } | ||
210 | "#, | ||
211 | expect![[r#" | ||
212 | kw mut | ||
213 | ev E::X () | ||
214 | en E | ||
215 | ma m!(…) macro_rules! m | ||
216 | "#]], | ||
217 | ); | ||
218 | } | ||
219 | |||
220 | #[test] | ||
221 | fn omits_private_fields_pat() { | ||
222 | check( | ||
223 | r#" | ||
224 | mod foo { | ||
225 | pub struct Record { pub field: i32, _field: i32 } | ||
226 | pub struct Tuple(pub u32, u32); | ||
227 | pub struct Invisible(u32, u32); | ||
228 | } | ||
229 | use foo::*; | ||
230 | |||
231 | fn outer() { | ||
232 | if let a$0 | ||
233 | } | ||
234 | "#, | ||
235 | expect![[r#" | ||
236 | kw mut | ||
237 | bn Record Record { field$1, .. }$0 | ||
238 | st Record | ||
239 | bn Tuple Tuple($1, ..)$0 | ||
240 | st Tuple | ||
241 | st Invisible | ||
242 | md foo | ||
243 | "#]], | ||
244 | ) | ||
245 | } | ||
246 | |||
247 | // #[test] | ||
248 | // fn only_shows_ident_completion() { | ||
249 | // check_edit( | ||
250 | // "Foo", | ||
251 | // r#" | ||
252 | // struct Foo(i32); | ||
253 | // fn main() { | ||
254 | // match Foo(92) { | ||
255 | // a$0(92) => (), | ||
256 | // } | ||
257 | // } | ||
258 | // "#, | ||
259 | // r#" | ||
260 | // struct Foo(i32); | ||
261 | // fn main() { | ||
262 | // match Foo(92) { | ||
263 | // Foo(92) => (), | ||
264 | // } | ||
265 | // } | ||
266 | // "#, | ||
267 | // ); | ||
268 | // } | ||
269 | |||
270 | #[test] | ||
271 | fn completes_self_pats() { | ||
272 | check( | ||
273 | r#" | ||
274 | struct Foo(i32); | ||
275 | impl Foo { | ||
276 | fn foo() { | ||
277 | match Foo(0) { | ||
278 | a$0 | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | "#, | ||
283 | expect![[r#" | ||
284 | kw mut | ||
285 | bn Self Self($1)$0 | ||
286 | sp Self | ||
287 | bn Foo Foo($1)$0 | ||
288 | st Foo | ||
289 | "#]], | ||
290 | ) | ||
291 | } | ||
292 | |||
293 | #[test] | ||
294 | fn completes_qualified_variant() { | ||
295 | check( | ||
296 | r#" | ||
297 | enum Foo { | ||
298 | Bar { baz: i32 } | ||
299 | } | ||
300 | impl Foo { | ||
301 | fn foo() { | ||
302 | match {Foo::Bar { baz: 0 }} { | ||
303 | B$0 | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | "#, | ||
308 | expect![[r#" | ||
309 | kw mut | ||
310 | bn Self::Bar Self::Bar { baz$1 }$0 | ||
311 | ev Self::Bar { baz: i32 } | ||
312 | bn Foo::Bar Foo::Bar { baz$1 }$0 | ||
313 | ev Foo::Bar { baz: i32 } | ||
314 | sp Self | ||
315 | en Foo | ||
316 | "#]], | ||
317 | ) | ||
318 | } | ||
319 | |||
320 | #[test] | ||
321 | fn completes_in_record_field_pat() { | ||
322 | check( | ||
323 | r#" | ||
324 | struct Foo { bar: Bar } | ||
325 | struct Bar(u32); | ||
326 | fn outer(Foo { bar: $0 }: Foo) {} | ||
327 | "#, | ||
328 | expect![[r#" | ||
329 | kw mut | ||
330 | bn Foo Foo { bar$1 }$0 | ||
331 | st Foo | ||
332 | bn Bar Bar($1)$0 | ||
333 | st Bar | ||
334 | "#]], | ||
335 | ) | ||
336 | } | ||
337 | |||
338 | #[test] | ||
339 | fn skips_in_record_field_pat_name() { | ||
340 | check( | ||
341 | r#" | ||
342 | struct Foo { bar: Bar } | ||
343 | struct Bar(u32); | ||
344 | fn outer(Foo { bar$0 }: Foo) {} | ||
345 | "#, | ||
346 | expect![[r#""#]], | ||
347 | ) | ||
348 | } | ||
diff --git a/crates/ide_completion/src/tests/type_pos.rs b/crates/ide_completion/src/tests/type_pos.rs new file mode 100644 index 000000000..1ab47b27e --- /dev/null +++ b/crates/ide_completion/src/tests/type_pos.rs | |||
@@ -0,0 +1,177 @@ | |||
1 | //! Completions tests for type position. | ||
2 | use expect_test::{expect, Expect}; | ||
3 | |||
4 | use crate::tests::completion_list; | ||
5 | |||
6 | fn check_with(ra_fixture: &str, expect: Expect) { | ||
7 | let base = r#" | ||
8 | enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV } | ||
9 | use self::Enum::TupleV; | ||
10 | mod module {} | ||
11 | |||
12 | trait Trait {} | ||
13 | static STATIC: Unit = Unit; | ||
14 | const CONST: Unit = Unit; | ||
15 | struct Record { field: u32 } | ||
16 | struct Tuple(u32); | ||
17 | struct Unit | ||
18 | macro_rules! makro {} | ||
19 | "#; | ||
20 | let actual = completion_list(&format!("{}\n{}", base, ra_fixture)); | ||
21 | expect.assert_eq(&actual) | ||
22 | } | ||
23 | |||
24 | #[test] | ||
25 | fn record_field_ty() { | ||
26 | check_with( | ||
27 | r#" | ||
28 | struct Foo<'lt, T, const C: usize> { | ||
29 | f: $0 | ||
30 | } | ||
31 | "#, | ||
32 | expect![[r#" | ||
33 | sp Self | ||
34 | tp T | ||
35 | tt Trait | ||
36 | en Enum | ||
37 | st Record | ||
38 | st Tuple | ||
39 | md module | ||
40 | st Foo<…> | ||
41 | st Unit | ||
42 | ma makro!(…) macro_rules! makro | ||
43 | bt u32 | ||
44 | "#]], | ||
45 | ) | ||
46 | } | ||
47 | |||
48 | #[test] | ||
49 | fn tuple_struct_field() { | ||
50 | check_with( | ||
51 | r#" | ||
52 | struct Foo<'lt, T, const C: usize>(f$0); | ||
53 | "#, | ||
54 | expect![[r#" | ||
55 | kw pub(crate) | ||
56 | kw pub | ||
57 | sp Self | ||
58 | tp T | ||
59 | tt Trait | ||
60 | en Enum | ||
61 | st Record | ||
62 | st Tuple | ||
63 | md module | ||
64 | st Foo<…> | ||
65 | st Unit | ||
66 | ma makro!(…) macro_rules! makro | ||
67 | bt u32 | ||
68 | "#]], | ||
69 | ) | ||
70 | } | ||
71 | |||
72 | #[test] | ||
73 | fn fn_return_type() { | ||
74 | check_with( | ||
75 | r#" | ||
76 | fn x<'lt, T, const C: usize>() -> $0 | ||
77 | "#, | ||
78 | expect![[r#" | ||
79 | tp T | ||
80 | tt Trait | ||
81 | en Enum | ||
82 | st Record | ||
83 | st Tuple | ||
84 | md module | ||
85 | st Unit | ||
86 | ma makro!(…) macro_rules! makro | ||
87 | bt u32 | ||
88 | "#]], | ||
89 | ); | ||
90 | } | ||
91 | |||
92 | #[test] | ||
93 | fn body_type_pos() { | ||
94 | check_with( | ||
95 | r#" | ||
96 | fn foo<'lt, T, const C: usize>() { | ||
97 | let local = (); | ||
98 | let _: $0; | ||
99 | } | ||
100 | "#, | ||
101 | expect![[r#" | ||
102 | tp T | ||
103 | tt Trait | ||
104 | en Enum | ||
105 | st Record | ||
106 | st Tuple | ||
107 | md module | ||
108 | st Unit | ||
109 | ma makro!(…) macro_rules! makro | ||
110 | bt u32 | ||
111 | "#]], | ||
112 | ); | ||
113 | check_with( | ||
114 | r#" | ||
115 | fn foo<'lt, T, const C: usize>() { | ||
116 | let local = (); | ||
117 | let _: self::$0; | ||
118 | } | ||
119 | "#, | ||
120 | expect![[r#" | ||
121 | tt Trait | ||
122 | en Enum | ||
123 | st Record | ||
124 | st Tuple | ||
125 | md module | ||
126 | st Unit | ||
127 | "#]], | ||
128 | ); | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn completes_types_and_const_in_arg_list() { | ||
133 | // FIXME: we should complete the lifetime here for now | ||
134 | check_with( | ||
135 | r#" | ||
136 | trait Trait2 { | ||
137 | type Foo; | ||
138 | } | ||
139 | |||
140 | fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} | ||
141 | "#, | ||
142 | expect![[r#" | ||
143 | ta Foo = type Foo; | ||
144 | tp T | ||
145 | cp CONST_PARAM | ||
146 | tt Trait | ||
147 | en Enum | ||
148 | st Record | ||
149 | st Tuple | ||
150 | tt Trait2 | ||
151 | md module | ||
152 | st Unit | ||
153 | ct CONST | ||
154 | ma makro!(…) macro_rules! makro | ||
155 | bt u32 | ||
156 | "#]], | ||
157 | ); | ||
158 | check_with( | ||
159 | r#" | ||
160 | trait Trait2 { | ||
161 | type Foo; | ||
162 | } | ||
163 | |||
164 | fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {} | ||
165 | "#, | ||
166 | expect![[r#" | ||
167 | tt Trait | ||
168 | en Enum | ||
169 | st Record | ||
170 | st Tuple | ||
171 | tt Trait2 | ||
172 | md module | ||
173 | st Unit | ||
174 | ct CONST | ||
175 | "#]], | ||
176 | ); | ||
177 | } | ||
diff --git a/crates/ide_completion/src/tests/use_tree.rs b/crates/ide_completion/src/tests/use_tree.rs new file mode 100644 index 000000000..7e6748ccc --- /dev/null +++ b/crates/ide_completion/src/tests/use_tree.rs | |||
@@ -0,0 +1,255 @@ | |||
1 | use expect_test::{expect, Expect}; | ||
2 | |||
3 | use crate::tests::completion_list; | ||
4 | |||
5 | fn check(ra_fixture: &str, expect: Expect) { | ||
6 | let actual = completion_list(ra_fixture); | ||
7 | expect.assert_eq(&actual) | ||
8 | } | ||
9 | |||
10 | #[test] | ||
11 | fn use_tree_start() { | ||
12 | cov_mark::check!(only_completes_modules_in_import); | ||
13 | check( | ||
14 | r#" | ||
15 | //- /lib.rs crate:main deps:other_crate | ||
16 | use f$0 | ||
17 | |||
18 | struct Foo; | ||
19 | mod foo {} | ||
20 | //- /other_crate/lib.rs crate:other_crate | ||
21 | // nothing here | ||
22 | "#, | ||
23 | expect![[r#" | ||
24 | kw crate:: | ||
25 | kw self:: | ||
26 | kw super:: | ||
27 | md foo | ||
28 | md other_crate | ||
29 | "#]], | ||
30 | ); | ||
31 | } | ||
32 | |||
33 | #[test] | ||
34 | fn dont_complete_current_use() { | ||
35 | cov_mark::check!(dont_complete_current_use); | ||
36 | check(r#"use self::foo$0;"#, expect![[r#""#]]); | ||
37 | check( | ||
38 | r#" | ||
39 | mod foo { pub struct S; } | ||
40 | use self::{foo::*, bar$0}; | ||
41 | "#, | ||
42 | expect![[r#" | ||
43 | kw self | ||
44 | st S | ||
45 | md foo | ||
46 | "#]], | ||
47 | ); | ||
48 | } | ||
49 | |||
50 | #[test] | ||
51 | fn nested_use_tree() { | ||
52 | check( | ||
53 | r#" | ||
54 | mod foo { | ||
55 | pub mod bar { | ||
56 | pub struct FooBar; | ||
57 | } | ||
58 | } | ||
59 | use foo::{bar::$0} | ||
60 | "#, | ||
61 | expect![[r#" | ||
62 | st FooBar | ||
63 | "#]], | ||
64 | ); | ||
65 | check( | ||
66 | r#" | ||
67 | mod foo { | ||
68 | pub mod bar { | ||
69 | pub struct FooBar; | ||
70 | } | ||
71 | } | ||
72 | use foo::{$0} | ||
73 | "#, | ||
74 | expect![[r#" | ||
75 | kw self | ||
76 | md bar | ||
77 | "#]], | ||
78 | ); | ||
79 | } | ||
80 | |||
81 | #[test] | ||
82 | fn deeply_nested_use_tree() { | ||
83 | check( | ||
84 | r#" | ||
85 | mod foo { | ||
86 | pub mod bar { | ||
87 | pub mod baz { | ||
88 | pub struct FooBarBaz; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | use foo::{bar::{baz::$0}} | ||
93 | "#, | ||
94 | expect![[r#" | ||
95 | st FooBarBaz | ||
96 | "#]], | ||
97 | ); | ||
98 | check( | ||
99 | r#" | ||
100 | mod foo { | ||
101 | pub mod bar { | ||
102 | pub mod baz { | ||
103 | pub struct FooBarBaz; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | use foo::{bar::{$0}} | ||
108 | "#, | ||
109 | expect![[r#" | ||
110 | kw self | ||
111 | md baz | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn plain_qualified_use_tree() { | ||
118 | check( | ||
119 | r#" | ||
120 | use foo::$0 | ||
121 | |||
122 | mod foo { | ||
123 | struct Private; | ||
124 | pub struct Foo; | ||
125 | } | ||
126 | struct Bar; | ||
127 | "#, | ||
128 | expect![[r#" | ||
129 | st Foo | ||
130 | "#]], | ||
131 | ); | ||
132 | } | ||
133 | |||
134 | #[test] | ||
135 | fn self_qualified_use_tree() { | ||
136 | check( | ||
137 | r#" | ||
138 | use self::$0 | ||
139 | |||
140 | mod foo {} | ||
141 | struct Bar; | ||
142 | "#, | ||
143 | expect![[r#" | ||
144 | md foo | ||
145 | st Bar | ||
146 | "#]], | ||
147 | ); | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn super_qualified_use_tree() { | ||
152 | check( | ||
153 | r#" | ||
154 | mod bar { | ||
155 | use super::$0 | ||
156 | } | ||
157 | |||
158 | mod foo {} | ||
159 | struct Bar; | ||
160 | "#, | ||
161 | expect![[r#" | ||
162 | kw super:: | ||
163 | st Bar | ||
164 | md bar | ||
165 | md foo | ||
166 | "#]], | ||
167 | ); | ||
168 | } | ||
169 | |||
170 | #[test] | ||
171 | fn super_super_qualified_use_tree() { | ||
172 | check( | ||
173 | r#" | ||
174 | mod a { | ||
175 | const A: usize = 0; | ||
176 | mod b { | ||
177 | const B: usize = 0; | ||
178 | mod c { use super::super::$0 } | ||
179 | } | ||
180 | } | ||
181 | "#, | ||
182 | expect![[r#" | ||
183 | kw super:: | ||
184 | md b | ||
185 | ct A | ||
186 | "#]], | ||
187 | ); | ||
188 | } | ||
189 | |||
190 | #[test] | ||
191 | fn crate_qualified_use_tree() { | ||
192 | check( | ||
193 | r#" | ||
194 | use crate::$0 | ||
195 | |||
196 | mod foo {} | ||
197 | struct Bar; | ||
198 | "#, | ||
199 | expect![[r#" | ||
200 | md foo | ||
201 | st Bar | ||
202 | "#]], | ||
203 | ); | ||
204 | } | ||
205 | |||
206 | #[test] | ||
207 | fn extern_crate_qualified_use_tree() { | ||
208 | check( | ||
209 | r#" | ||
210 | //- /lib.rs crate:main deps:other_crate | ||
211 | use other_crate::$0 | ||
212 | //- /other_crate/lib.rs crate:other_crate | ||
213 | pub struct Foo; | ||
214 | pub mod foo {} | ||
215 | "#, | ||
216 | expect![[r#" | ||
217 | st Foo | ||
218 | md foo | ||
219 | "#]], | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn pub_use_tree() { | ||
225 | check( | ||
226 | r#" | ||
227 | pub struct X; | ||
228 | pub mod bar {} | ||
229 | pub use $0; | ||
230 | "#, | ||
231 | expect![[r#" | ||
232 | kw crate:: | ||
233 | kw self:: | ||
234 | kw super:: | ||
235 | md bar | ||
236 | "#]], | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn use_tree_braces_at_start() { | ||
242 | check( | ||
243 | r#" | ||
244 | struct X; | ||
245 | mod bar {} | ||
246 | use {$0}; | ||
247 | "#, | ||
248 | expect![[r#" | ||
249 | kw crate:: | ||
250 | kw self:: | ||
251 | kw super:: | ||
252 | md bar | ||
253 | "#]], | ||
254 | ); | ||
255 | } | ||