aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r--crates/ide_completion/src/completions.rs134
-rw-r--r--crates/ide_completion/src/completions/attribute.rs7
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs66
-rw-r--r--crates/ide_completion/src/completions/attribute/lint.rs3
-rw-r--r--crates/ide_completion/src/completions/attribute/repr.rs199
-rw-r--r--crates/ide_completion/src/completions/dot.rs9
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs6
-rw-r--r--crates/ide_completion/src/completions/fn_param.rs4
-rw-r--r--crates/ide_completion/src/completions/keyword.rs278
-rw-r--r--crates/ide_completion/src/completions/lifetime.rs13
-rw-r--r--crates/ide_completion/src/completions/mod_.rs138
-rw-r--r--crates/ide_completion/src/completions/pattern.rs397
-rw-r--r--crates/ide_completion/src/completions/postfix.rs31
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs336
-rw-r--r--crates/ide_completion/src/completions/record.rs30
-rw-r--r--crates/ide_completion/src/completions/snippet.rs32
-rw-r--r--crates/ide_completion/src/completions/trait_impl.rs313
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs278
-rw-r--r--crates/ide_completion/src/context.rs156
-rw-r--r--crates/ide_completion/src/item.rs2
-rw-r--r--crates/ide_completion/src/lib.rs123
-rw-r--r--crates/ide_completion/src/patterns.rs44
-rw-r--r--crates/ide_completion/src/render.rs212
-rw-r--r--crates/ide_completion/src/render/builder_ext.rs4
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs2
-rw-r--r--crates/ide_completion/src/render/function.rs2
-rw-r--r--crates/ide_completion/src/render/macro_.rs8
-rw-r--r--crates/ide_completion/src/tests.rs (renamed from crates/ide_completion/src/test_utils.rs)74
-rw-r--r--crates/ide_completion/src/tests/item_list.rs223
-rw-r--r--crates/ide_completion/src/tests/items.rs95
-rw-r--r--crates/ide_completion/src/tests/pattern.rs348
-rw-r--r--crates/ide_completion/src/tests/type_pos.rs177
-rw-r--r--crates/ide_completion/src/tests/use_tree.rs255
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
44impl Into<Vec<CompletionItem>> for Completions { 44impl 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
223fn 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.
213fn 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
18mod derive; 18mod derive;
19mod lint; 19mod lint;
20mod repr;
20 21
21pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 22pub(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] = &[
80mod tests { 82mod 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]
90pub macro Clone {}
91#[rustc_builtin_macro]
92pub macro Copy {}
93#[rustc_builtin_macro]
94pub macro Default {}
95#[rustc_builtin_macro]
96pub macro Debug {}
97#[rustc_builtin_macro]
98pub macro Hash {}
99#[rustc_builtin_macro]
100pub macro PartialEq {}
101#[rustc_builtin_macro]
102pub macro Eq {}
103#[rustc_builtin_macro]
104pub macro PartialOrd {}
105#[rustc_builtin_macro]
106pub 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)]
35mod tests { 35mod 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
3use syntax::ast;
4
5use crate::{
6 context::CompletionContext,
7 item::{CompletionItem, CompletionItemKind, CompletionKind},
8 Completions,
9};
10
11pub(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
41struct ReprCompletion {
42 label: &'static str,
43 snippet: Option<&'static str>,
44 lookup: Option<&'static str>,
45 collides: &'static [&'static str],
46}
47
48const fn attr(label: &'static str, collides: &'static [&'static str]) -> ReprCompletion {
49 ReprCompletion { label, snippet: None, lookup: None, collides }
50}
51
52#[rustfmt::skip]
53const 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)]
73mod 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(
101mod tests { 101mod 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
502trait FnOnce<Args> {
503 type Output;
504}
505struct S; 502struct S;
506 503
507struct Foo; 504struct 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)
64mod tests { 64mod 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
540use std::future::*; 412use core::future::*;
541struct A {} 413struct A {}
542impl Future for A {} 414impl Future for A {}
543fn foo(a: A) { a.$0 } 415fn foo(a: A) { a.$0 }
544
545//- /std/lib.rs crate:std
546pub 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
559use std::future::*; 425use std::future::*;
560fn foo() { 426fn foo() {
561 let a = async {}; 427 let a = async {};
562 a.$0 428 a.$0
563} 429}
564
565//- /std/lib.rs crate:std
566pub 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#"
601struct 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) {
49mod tests { 49mod 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)]
143mod tests { 143mod 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 157mod $0
158 //- /foo.rs 158//- /foo.rs
159 fn foo() {} 159fn foo() {}
160 //- /foo/ignored_foo.rs 160//- /foo/ignored_foo.rs
161 fn ignored_foo() {} 161fn ignored_foo() {}
162 //- /bar/mod.rs 162//- /bar/mod.rs
163 fn bar() {} 163fn bar() {}
164 //- /bar/ignored_bar.rs 164//- /bar/ignored_bar.rs
165 fn ignored_bar() {} 165fn 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 { 179mod $0 {
180 180
181 } 181}
182 //- /foo.rs 182//- /foo.rs
183 fn foo() {} 183fn 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 194mod $0
195 //- /foo.rs 195//- /foo.rs
196 fn foo() {} 196fn foo() {}
197 //- /foo/ignored_foo.rs 197//- /foo/ignored_foo.rs
198 fn ignored_foo() {} 198fn ignored_foo() {}
199 //- /bar/mod.rs 199//- /bar/mod.rs
200 fn bar() {} 200fn bar() {}
201 //- /bar/ignored_bar.rs 201//- /bar/ignored_bar.rs
202 fn ignored_bar() {} 202fn 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 { 216mod tests {
217 mod $0; 217 mod $0;
218 } 218}
219 //- /tests/foo.rs 219//- /tests/foo.rs
220 fn foo() {} 220fn 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; 233mod foo;
234 //- /foo.rs 234//- /foo.rs
235 mod $0; 235mod $0;
236 //- /foo/bar.rs 236//- /foo/bar.rs
237 fn bar() {} 237fn bar() {}
238 //- /foo/bar/ignored_bar.rs 238//- /foo/bar/ignored_bar.rs
239 fn ignored_bar() {} 239fn ignored_bar() {}
240 //- /foo/baz/mod.rs 240//- /foo/baz/mod.rs
241 fn baz() {} 241fn baz() {}
242 //- /foo/moar/ignored_moar.rs 242//- /foo/moar/ignored_moar.rs
243 fn ignored_moar() {} 243fn 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; 257mod foo;
258 //- /foo.rs 258//- /foo.rs
259 mod bar { 259mod bar {
260 mod $0 260 mod $0
261 } 261}
262 //- /foo/bar/baz.rs 262//- /foo/bar/baz.rs
263 fn baz() {} 263fn 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() {} 303fn main() {}
304 //- /src/bin/foo.rs 304//- /src/bin/foo.rs
305 mod $0 305mod $0
306 //- /src/bin/bar.rs 306//- /src/bin/bar.rs
307 mod foo; 307mod foo;
308 fn bar() {} 308fn bar() {}
309 //- /src/bin/bar/bar_ignored.rs 309//- /src/bin/bar/bar_ignored.rs
310 fn bar_ignored() {} 310fn 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)]
60mod 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#"
82enum E { X }
83use self::E::X;
84const Z: E = E::X;
85mod m {}
86
87static FOO: E = E::X;
88struct Bar { f: u32 }
89
90fn 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#"
108macro_rules! m { ($e:expr) => { $e } }
109enum E { X }
110
111#[rustc_builtin_macro]
112macro Clone {}
113
114fn 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#"
130macro_rules! m { ($e:expr) => { $e } }
131enum E { X }
132
133fn 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#"
149enum E { X }
150use self::E::X;
151const Z: E = E::X;
152mod m {}
153
154static FOO: E = E::X;
155struct Bar { f: u32 }
156
157fn 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#"
171enum E { X }
172
173static FOO: E = E::X;
174struct Bar { f: u32 }
175
176fn 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#"
189struct Bar { f: u32 }
190
191fn 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#"
205struct Foo { bar: String, baz: String }
206struct Bar(String, String);
207struct Baz;
208fn 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#"
221struct Foo { bar: String, baz: String }
222struct Bar(String, String);
223struct Baz;
224fn 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#"
239struct Foo { bar: i32, baz: i32 }
240struct Bar(String, String);
241struct Baz;
242fn 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#"
259mod foo {
260 pub struct Foo { pub bar: i32, baz: i32 }
261 pub struct Bar(pub String, String);
262 pub struct Invisible(String, String);
263}
264use foo::*;
265
266fn 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#"
284struct Foo(i32);
285fn main() {
286 match Foo(92) {
287 a$0(92) => (),
288 }
289}
290"#,
291 r#"
292struct Foo(i32);
293fn 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#"
306struct Foo(i32);
307impl 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#"
326enum Foo {
327 Bar { baz: i32 }
328}
329impl 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#"
348enum Foo { Bar, Baz, Quux }
349
350fn 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#"
368enum Foo { Bar, Baz, Quux }
369
370fn 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#"
388enum Foo { Bar, Baz, Quux }
389
390fn 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#"
408enum Foo { Bar, Baz, Quux }
409impl 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#"
430struct Foo { bar: Bar }
431struct Bar(u32);
432fn 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#"
445struct Foo { bar: Bar }
446struct Bar(u32);
447fn 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#"
439enum Option<T> { Some(T), None } 439//- minicore: option
440
441fn main() { 440fn 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#"
447enum Option<T> { Some(T), None }
448
449fn main() { 446fn 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#"
464enum Result<T, E> { Ok(T), Err(E) } 461//- minicore: result
465
466fn main() { 462fn 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#"
472enum Result<T, E> { Ok(T), Err(E) }
473
474fn main() { 468fn 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#"
518enum Option<T> { Some(T), None } 512//- minicore: option
519
520fn main() { 513fn 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#"
526enum Option<T> { Some(T), None }
527
528fn main() { 519fn 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
179fn add_enum_variants(ctx: &CompletionContext, acc: &mut Completions, e: hir::Enum) { 184fn 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
195fn 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)]
186mod tests { 203mod 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#"
214const FOO: () = ();
215static BAR: () = ();
216struct Baz;
217fn 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#"
231enum Foo { Bar }
232fn 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#"
244mod foo { pub struct S; }
245use 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#"
294use self::my::$0;
295
296mod my { pub struct Bar; }
297fn my() {}
298"#,
299 expect![[r#"
300 st Bar
301 "#]],
302 );
303 }
304
305 #[test]
306 fn filters_visibility() {
307 check(
308 r#"
309use self::my::$0;
310
311mod 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#"
328use self::m::$0;
329
330mod 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
343mod foo;
344struct Spam;
345//- /foo.rs
346use 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
360mod foo;
361struct Spam;
362//- /foo.rs
363use 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
377mod foo;
378pub mod bar {
379 pub mod baz {
380 pub struct Spam;
381 }
382}
383//- /foo.rs
384use 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
493use foo::$0;
494
495//- /foo/lib.rs crate:foo
496pub 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]
690macro_rules! foo { () => {} }
691mod bar {}
692
693struct MyStruct {}
694impl 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#"
709struct MyStruct {}
710#[macro_export]
711macro_rules! foo {}
712mod bar {}
713
714crate::$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#"
727mod 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)]
49mod tests { 49mod 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
86struct S { foo: u32, bar: usize } 71struct S { foo: u32, bar: usize }
87 72
88impl core::default::Default for S { 73impl 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
124struct S { foo: u32, bar: usize } 110struct S { foo: u32, bar: usize }
125 111
126impl core::default::Default for S { 112impl 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#"
143struct S { foo: u32, bar: usize } 129struct S { foo: u32, bar: usize }
144 130
145impl core::default::Default for S { 131impl 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
3use ide_db::helpers::SnippetCap; 3use ide_db::helpers::SnippetCap;
4use syntax::T;
4 5
5use crate::{ 6use 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
37pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { 38pub(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}() {
82mod tests { 91mod 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)]
114mod 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
34use hir::{self, HasAttrs, HasSource}; 34use hir::{self, HasAttrs, HasSource};
35use ide_db::{traits::get_missing_assoc_items, SymbolKind}; 35use ide_db::{path_transform::PathTransform, traits::get_missing_assoc_items, SymbolKind};
36use syntax::{ 36use 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
53pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 53pub(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.
180fn 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
167fn add_type_alias_impl( 202fn 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#"
832trait Foo<T> {
833 fn function() -> T;
834}
835struct Bar;
836
837impl Foo<u32> for Bar {
838 fn f$0
839}
840"#,
841 r#"
842trait Foo<T> {
843 fn function() -> T;
844}
845struct Bar;
846
847impl 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#"
861trait Foo<T> {
862 fn function(bar: T);
863}
864struct Bar;
865
866impl Foo<u32> for Bar {
867 fn f$0
868}
869"#,
870 r#"
871trait Foo<T> {
872 fn function(bar: T);
873}
874struct Bar;
875
876impl 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#"
890trait Foo<T> {
891 fn function(bar: Vec<T>);
892}
893struct Bar;
894
895impl Foo<u32> for Bar {
896 fn f$0
897}
898"#,
899 r#"
900trait Foo<T> {
901 fn function(bar: Vec<T>);
902}
903struct Bar;
904
905impl 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#"
919trait Foo<T, U, V> {
920 fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
921}
922struct Bar;
923
924impl Foo<u32, Vec<usize>, u8> for Bar {
925 fn f$0
926}
927"#,
928 r#"
929trait Foo<T, U, V> {
930 fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
931}
932struct Bar;
933
934impl 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#"
948trait Foo<T> {
949 const BAR: T;
950}
951struct Bar;
952
953impl Foo<u32> for Bar {
954 const B$0;
955}
956"#,
957 r#"
958trait Foo<T> {
959 const BAR: T;
960}
961struct Bar;
962
963impl 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#"
975trait SomeTrait<T> {}
976
977trait Foo<T> {
978 fn function()
979 where Self: SomeTrait<T>;
980}
981struct Bar;
982
983impl Foo<u32> for Bar {
984 fn f$0
985}
986"#,
987 r#"
988trait SomeTrait<T> {}
989
990trait Foo<T> {
991 fn function()
992 where Self: SomeTrait<T>;
993}
994struct Bar;
995
996impl Foo<u32> for Bar {
997 fn function()
998where 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};
6use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; 6use crate::{patterns::ImmediateLocation, CompletionContext, Completions};
7 7
8pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 8pub(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#"
98const FOO: () = ();
99static BAR: () = ();
100enum Foo {
101 Bar
102}
103struct Baz;
104fn 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#"
121use f$0
122
123struct Foo;
124mod 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#"
136enum Enum { A, B }
137fn 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#"
152enum Enum { A, B }
153fn 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#"
168enum Enum { A, B }
169fn 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
350use $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#"
382struct Foo;
383fn 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]
488pub macro Clone {}
489
490struct S;
491impl S {
492 $0
493}
494"#,
495 expect![[r#""#]],
496 );
497 check(
498 r#"
499#[rustc_builtin_macro]
500pub macro bench {} 369pub macro bench {}
501 370
502fn f() {$0} 371fn 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#"
588macro_rules! foo { () => {} }
589fn 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#"
747trait MyTrait {}
748struct MyStruct {}
749
750impl 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#"
764macro_rules! foo {}
765mod bar {}
766
767struct MyStruct {}
768impl 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#"
783struct MyStruct {}
784macro_rules! foo {}
785mod 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#"
800trait Foo {
801 type Bar;
802}
803
804fn 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
670fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> { 699fn 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
708fn 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#"
755fn foo() { 797fn foo() { bar($0); }
756 bar($0); 798fn bar(x: u32) {}
757} 799"#,
758 800 expect![[r#"ty: u32, name: x"#]],
801 );
802 check_expected_type_and_name(
803 r#"
804fn foo() { bar(c$0); }
759fn bar(x: u32) {} 805fn 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#"
770fn foo() { 816fn foo() { bar(&$0); }
771 bar(c$0); 817fn bar(x: &u32) {}
772} 818"#,
773 819 expect![[r#"ty: u32, name: x"#]],
774fn bar(x: u32) {} 820 );
821 check_expected_type_and_name(
822 r#"
823fn foo() { bar(&mut $0); }
824fn 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#"
830fn foo() { bar(&c$0); }
831fn 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
924fn foo() { 982fn foo() {
925 bar(|| a$0); 983 bar(|| a$0);
926} 984}
927 985
928fn bar(f: impl FnOnce() -> u32) {} 986fn bar(f: impl FnOnce() -> u32) {}
929#[lang = "fn_once"]
930trait 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
3mod completions;
3mod config; 4mod config;
4mod item;
5mod context; 5mod context;
6mod item;
6mod patterns; 7mod patterns;
7#[cfg(test)]
8mod test_utils;
9mod render; 8mod render;
10 9
11mod completions; 10#[cfg(test)]
11mod tests;
12 12
13use completions::flyimport::position_for_import; 13use completions::flyimport::position_for_import;
14use ide_db::{ 14use 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)]
205mod 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#"
253macro_rules! bar {
254 () => {
255 struct Bar;
256 impl Bar {
257 #[doc = "Do the foo"]
258 fn foo(&self) {}
259 }
260 }
261}
262
263bar!();
264
265fn 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#"
278macro_rules! bar {
279 () => {
280 struct Bar;
281 impl Bar {
282 /// Do the foo
283 fn foo(&self) {}
284 }
285 }
286}
287
288bar!();
289
290fn 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
307fn foo() -> &'static str { "foo" }
308
309fn 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)]
14use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; 14use 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)]
26pub(crate) enum ImmediateLocation { 28pub(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> {
310mod tests { 334mod 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
27pub(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
36pub(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
45pub(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
53pub(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)]
75pub(crate) struct RenderContext<'a> { 28pub(crate) struct RenderContext<'a> {
@@ -122,7 +75,7 @@ impl<'a> RenderContext<'a> {
122 } 75 }
123} 76}
124 77
125fn render_field_( 78pub(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
159fn render_tuple_field_( 109pub(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
126pub(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
134pub(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
178fn render_resolution_( 151fn 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#"
1089struct S; 1062struct S;
1090fn foo(s: &mut S) {} 1063fn 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#"
1079struct S;
1080fn foo(s: &mut S) {}
1081fn 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
1156trait Deref {
1157 type Target;
1158 fn deref(&self) -> &Self::Target;
1159}
1160
1161struct S; 1100struct S;
1162struct T(S); 1101struct T(S);
1163 1102
1164impl Deref for T { 1103impl 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
1199trait Deref {
1200 type Target;
1201 fn deref(&self) -> &Self::Target;
1202}
1203
1204#[lang = "deref_mut"]
1205pub trait DerefMut: Deref {
1206 fn deref_mut(&mut self) -> &mut Self::Target;
1207}
1208
1209struct S; 1139struct S;
1210struct T(S); 1140struct T(S);
1211 1141
1212impl Deref for T { 1142impl 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
1220impl DerefMut for T { 1150impl 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
1314trait Deref {
1315 type Target;
1316 fn deref(&self) -> &Self::Target;
1317}
1318
1319struct S; 1244struct S;
1320struct T(S); 1245struct T(S);
1321 1246
1322impl Deref for T { 1247impl 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 {}
1333fn main() { 1258fn 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)]
123mod tests { 123mod 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)]
192mod tests { 192mod 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)]
135mod tests { 135mod 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/// ```
181macro_rules! vec { () => {} } 181macro_rules! vec { () => {} }
182 182
183fn fn main() { v$0 } 183fn 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/// ```
194macro_rules! vec { () => {} } 194macro_rules! vec { () => {} }
195 195
196fn fn main() { vec![$0] } 196fn 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
7mod item_list;
8mod use_tree;
9mod items;
10mod pattern;
11mod type_pos;
12
13use std::mem;
2 14
3use hir::{PrefixKind, Semantics}; 15use hir::{PrefixKind, Semantics};
4use ide_db::{ 16use 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
47pub(crate) fn completion_list(code: &str) -> String {
48 completion_list_with_config(TEST_CONFIG, code)
49}
50
51fn 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.
35pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { 65pub(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
60pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { 90pub(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
64pub(crate) fn completion_list_with_config( 94pub(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() 104fn 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
96fn monospace_width(s: &str) -> usize {
97 s.chars().count()
98}
99
100pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 129pub(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
185fn 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]
195fn 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 @@
1use expect_test::{expect, Expect};
2
3use crate::tests::completion_list;
4
5fn check(ra_fixture: &str, expect: Expect) {
6 let base = r#"#[rustc_builtin_macro]
7pub macro Clone {}
8enum Enum { Variant }
9struct Struct {}
10#[macro_export]
11macro_rules! foo {}
12mod bar {}
13const CONST: () = ();
14trait Trait {}
15"#;
16 let actual = completion_list(&format!("{}{}", base, ra_fixture));
17 expect.assert_eq(&actual)
18}
19
20#[test]
21fn 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]
49fn 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]
79fn 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]
106fn 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]
132fn 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]
144fn 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]
164fn 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]
177fn 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]
195fn 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]
210fn 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_].
5use expect_test::{expect, Expect};
6
7use crate::tests::completion_list;
8
9fn check(ra_fixture: &str, expect: Expect) {
10 let base = r#"#[rustc_builtin_macro]
11pub macro Clone {}
12enum Enum { Variant }
13struct Struct {}
14#[macro_export]
15macro_rules! foo {}
16mod bar {}
17const CONST: () = ();
18trait Trait {}
19"#;
20 let actual = completion_list(&format!("{}{}", base, ra_fixture));
21 expect.assert_eq(&actual)
22}
23
24#[test]
25fn target_type_or_trait_in_impl_block() {
26 check(
27 r#"
28impl 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]
43fn target_type_in_trait_impl_block() {
44 check(
45 r#"
46impl 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]
61fn 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]
71fn 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]
82fn before_record_field() {
83 check(
84 r#"
85struct 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.
2use expect_test::{expect, Expect};
3
4use crate::tests::completion_list;
5
6fn check(ra_fixture: &str, expect: Expect) {
7 let actual = completion_list(ra_fixture);
8 expect.assert_eq(&actual)
9}
10
11fn check_with(ra_fixture: &str, expect: Expect) {
12 let base = r#"
13enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
14use self::Enum::TupleV;
15mod module {}
16
17static STATIC: Unit = Unit;
18const CONST: Unit = Unit;
19struct Record { field: u32 }
20struct Tuple(u32);
21struct Unit
22macro_rules! makro {}
23"#;
24 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
25 expect.assert_eq(&actual)
26}
27
28#[test]
29fn ident_rebind_pat() {
30 check(
31 r#"
32fn quux() {
33 let en$0 @ x
34}
35"#,
36 expect![[r#"
37 kw mut
38 "#]],
39 );
40}
41
42#[test]
43fn ident_ref_pat() {
44 check(
45 r#"
46fn quux() {
47 let ref en$0
48}
49"#,
50 expect![[r#"
51 kw mut
52 "#]],
53 );
54 check(
55 r#"
56fn quux() {
57 let ref en$0 @ x
58}
59"#,
60 expect![[r#"
61 kw mut
62 "#]],
63 );
64}
65
66#[test]
67fn ident_ref_mut_pat() {
68 // FIXME mut is already here, don't complete it again
69 check(
70 r#"
71fn quux() {
72 let ref mut en$0
73}
74"#,
75 expect![[r#"
76 kw mut
77 "#]],
78 );
79 check(
80 r#"
81fn quux() {
82 let ref mut en$0 @ x
83}
84"#,
85 expect![[r#"
86 kw mut
87 "#]],
88 );
89}
90
91#[test]
92fn ref_pat() {
93 check(
94 r#"
95fn 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#"
106fn quux() {
107 let &mut en$0
108}
109"#,
110 expect![[r#"
111 kw mut
112 "#]],
113 );
114}
115
116#[test]
117fn refutable() {
118 check_with(
119 r#"
120fn 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]
142fn irrefutable() {
143 check_with(
144 r#"
145fn 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]
162fn in_param() {
163 check_with(
164 r#"
165fn 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]
181fn only_fn_like_macros() {
182 check(
183 r#"
184macro_rules! m { ($e:expr) => { $e } }
185
186#[rustc_builtin_macro]
187macro Clone {}
188
189fn 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]
201fn in_simple_macro_call() {
202 check(
203 r#"
204macro_rules! m { ($e:expr) => { $e } }
205enum E { X }
206
207fn 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]
221fn omits_private_fields_pat() {
222 check(
223 r#"
224mod foo {
225 pub struct Record { pub field: i32, _field: i32 }
226 pub struct Tuple(pub u32, u32);
227 pub struct Invisible(u32, u32);
228}
229use foo::*;
230
231fn 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]
271fn completes_self_pats() {
272 check(
273 r#"
274struct Foo(i32);
275impl 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]
294fn completes_qualified_variant() {
295 check(
296 r#"
297enum Foo {
298 Bar { baz: i32 }
299}
300impl 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]
321fn completes_in_record_field_pat() {
322 check(
323 r#"
324struct Foo { bar: Bar }
325struct Bar(u32);
326fn 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]
339fn skips_in_record_field_pat_name() {
340 check(
341 r#"
342struct Foo { bar: Bar }
343struct Bar(u32);
344fn 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.
2use expect_test::{expect, Expect};
3
4use crate::tests::completion_list;
5
6fn check_with(ra_fixture: &str, expect: Expect) {
7 let base = r#"
8enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
9use self::Enum::TupleV;
10mod module {}
11
12trait Trait {}
13static STATIC: Unit = Unit;
14const CONST: Unit = Unit;
15struct Record { field: u32 }
16struct Tuple(u32);
17struct Unit
18macro_rules! makro {}
19"#;
20 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
21 expect.assert_eq(&actual)
22}
23
24#[test]
25fn record_field_ty() {
26 check_with(
27 r#"
28struct 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]
49fn tuple_struct_field() {
50 check_with(
51 r#"
52struct 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]
73fn fn_return_type() {
74 check_with(
75 r#"
76fn 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]
93fn body_type_pos() {
94 check_with(
95 r#"
96fn 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#"
115fn 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]
132fn completes_types_and_const_in_arg_list() {
133 // FIXME: we should complete the lifetime here for now
134 check_with(
135 r#"
136trait Trait2 {
137 type Foo;
138}
139
140fn 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#"
160trait Trait2 {
161 type Foo;
162}
163
164fn 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 @@
1use expect_test::{expect, Expect};
2
3use crate::tests::completion_list;
4
5fn check(ra_fixture: &str, expect: Expect) {
6 let actual = completion_list(ra_fixture);
7 expect.assert_eq(&actual)
8}
9
10#[test]
11fn use_tree_start() {
12 cov_mark::check!(only_completes_modules_in_import);
13 check(
14 r#"
15//- /lib.rs crate:main deps:other_crate
16use f$0
17
18struct Foo;
19mod 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]
34fn 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#"
39mod foo { pub struct S; }
40use self::{foo::*, bar$0};
41"#,
42 expect![[r#"
43 kw self
44 st S
45 md foo
46 "#]],
47 );
48}
49
50#[test]
51fn nested_use_tree() {
52 check(
53 r#"
54mod foo {
55 pub mod bar {
56 pub struct FooBar;
57 }
58}
59use foo::{bar::$0}
60"#,
61 expect![[r#"
62 st FooBar
63 "#]],
64 );
65 check(
66 r#"
67mod foo {
68 pub mod bar {
69 pub struct FooBar;
70 }
71}
72use foo::{$0}
73"#,
74 expect![[r#"
75 kw self
76 md bar
77 "#]],
78 );
79}
80
81#[test]
82fn deeply_nested_use_tree() {
83 check(
84 r#"
85mod foo {
86 pub mod bar {
87 pub mod baz {
88 pub struct FooBarBaz;
89 }
90 }
91}
92use foo::{bar::{baz::$0}}
93"#,
94 expect![[r#"
95 st FooBarBaz
96 "#]],
97 );
98 check(
99 r#"
100mod foo {
101 pub mod bar {
102 pub mod baz {
103 pub struct FooBarBaz;
104 }
105 }
106}
107use foo::{bar::{$0}}
108"#,
109 expect![[r#"
110 kw self
111 md baz
112 "#]],
113 );
114}
115
116#[test]
117fn plain_qualified_use_tree() {
118 check(
119 r#"
120use foo::$0
121
122mod foo {
123 struct Private;
124 pub struct Foo;
125}
126struct Bar;
127"#,
128 expect![[r#"
129 st Foo
130 "#]],
131 );
132}
133
134#[test]
135fn self_qualified_use_tree() {
136 check(
137 r#"
138use self::$0
139
140mod foo {}
141struct Bar;
142"#,
143 expect![[r#"
144 md foo
145 st Bar
146 "#]],
147 );
148}
149
150#[test]
151fn super_qualified_use_tree() {
152 check(
153 r#"
154mod bar {
155 use super::$0
156}
157
158mod foo {}
159struct Bar;
160"#,
161 expect![[r#"
162 kw super::
163 st Bar
164 md bar
165 md foo
166 "#]],
167 );
168}
169
170#[test]
171fn super_super_qualified_use_tree() {
172 check(
173 r#"
174mod 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]
191fn crate_qualified_use_tree() {
192 check(
193 r#"
194use crate::$0
195
196mod foo {}
197struct Bar;
198"#,
199 expect![[r#"
200 md foo
201 st Bar
202 "#]],
203 );
204}
205
206#[test]
207fn extern_crate_qualified_use_tree() {
208 check(
209 r#"
210//- /lib.rs crate:main deps:other_crate
211use other_crate::$0
212//- /other_crate/lib.rs crate:other_crate
213pub struct Foo;
214pub mod foo {}
215"#,
216 expect![[r#"
217 st Foo
218 md foo
219 "#]],
220 );
221}
222
223#[test]
224fn pub_use_tree() {
225 check(
226 r#"
227pub struct X;
228pub mod bar {}
229pub use $0;
230"#,
231 expect![[r#"
232 kw crate::
233 kw self::
234 kw super::
235 md bar
236 "#]],
237 );
238}
239
240#[test]
241fn use_tree_braces_at_start() {
242 check(
243 r#"
244struct X;
245mod bar {}
246use {$0};
247"#,
248 expect![[r#"
249 kw crate::
250 kw self::
251 kw super::
252 md bar
253 "#]],
254 );
255}