aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion')
-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"#,