aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r--crates/ide_completion/src/completions/keyword.rs28
-rw-r--r--crates/ide_completion/src/completions/pattern.rs395
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs76
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs147
-rw-r--r--crates/ide_completion/src/context.rs72
-rw-r--r--crates/ide_completion/src/patterns.rs9
-rw-r--r--crates/ide_completion/src/render.rs75
-rw-r--r--crates/ide_completion/src/tests.rs15
-rw-r--r--crates/ide_completion/src/tests/items.rs32
-rw-r--r--crates/ide_completion/src/tests/pattern.rs348
-rw-r--r--crates/ide_completion/src/tests/type_pos.rs177
11 files changed, 629 insertions, 745 deletions
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 07541c79c..407f796ef 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -92,7 +92,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
92 } 92 }
93 93
94 if !ctx.has_visibility_prev_sibling() 94 if !ctx.has_visibility_prev_sibling()
95 && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field()) 95 && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field())
96 { 96 {
97 add_keyword("pub(crate)", "pub(crate) "); 97 add_keyword("pub(crate)", "pub(crate) ");
98 add_keyword("pub", "pub "); 98 add_keyword("pub", "pub ");
@@ -122,6 +122,10 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
122 add_keyword("union", "union $1 {\n $0\n}"); 122 add_keyword("union", "union $1 {\n $0\n}");
123 } 123 }
124 124
125 if ctx.expects_type() {
126 return;
127 }
128
125 if ctx.expects_expression() { 129 if ctx.expects_expression() {
126 if !has_block_expr_parent { 130 if !has_block_expr_parent {
127 add_keyword("unsafe", "unsafe {\n $0\n}"); 131 add_keyword("unsafe", "unsafe {\n $0\n}");
@@ -373,28 +377,6 @@ fn quux() -> i32 {
373 } 377 }
374 378
375 #[test] 379 #[test]
376 fn test_mut_in_ref_and_in_fn_parameters_list() {
377 check(
378 r"fn my_fn(&$0) {}",
379 expect![[r#"
380 kw mut
381 "#]],
382 );
383 check(
384 r"fn my_fn($0) {}",
385 expect![[r#"
386 kw mut
387 "#]],
388 );
389 check(
390 r"fn my_fn() { let &$0 }",
391 expect![[r#"
392 kw mut
393 "#]],
394 );
395 }
396
397 #[test]
398 fn no_keyword_completion_in_comments() { 380 fn no_keyword_completion_in_comments() {
399 cov_mark::check!(no_keyword_completion_in_comments); 381 cov_mark::check!(no_keyword_completion_in_comments);
400 check( 382 check(
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index efe3c957a..bd13a62d7 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -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 tests::{check_edit, filtered_completion_list},
65 CompletionKind,
66 };
67
68 fn check(ra_fixture: &str, expect: Expect) {
69 let actual = filtered_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 = filtered_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/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index f5dbd203b..1b8997ecf 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -219,36 +219,6 @@ mod tests {
219 } 219 }
220 220
221 #[test] 221 #[test]
222 fn dont_complete_values_in_type_pos() {
223 check(
224 r#"
225const FOO: () = ();
226static BAR: () = ();
227struct Baz;
228fn foo() {
229 let _: self::$0;
230}
231"#,
232 expect![[r#"
233 st Baz
234 "#]],
235 );
236 }
237
238 #[test]
239 fn dont_complete_enum_variants_in_type_pos() {
240 check(
241 r#"
242enum Foo { Bar }
243fn foo() {
244 let _: Foo::$0;
245}
246"#,
247 expect![[r#""#]],
248 );
249 }
250
251 #[test]
252 fn dont_complete_primitive_in_use() { 222 fn dont_complete_primitive_in_use() {
253 check_builtin(r#"use self::$0;"#, expect![[""]]); 223 check_builtin(r#"use self::$0;"#, expect![[""]]);
254 } 224 }
@@ -259,32 +229,6 @@ fn foo() {
259 } 229 }
260 230
261 #[test] 231 #[test]
262 fn completes_primitives() {
263 check_builtin(
264 r#"fn main() { let _: $0 = 92; }"#,
265 expect![[r#"
266 bt u32
267 bt bool
268 bt u8
269 bt isize
270 bt u16
271 bt u64
272 bt u128
273 bt f32
274 bt i128
275 bt i16
276 bt str
277 bt i64
278 bt char
279 bt f64
280 bt i32
281 bt i8
282 bt usize
283 "#]],
284 );
285 }
286
287 #[test]
288 fn completes_enum_variant() { 232 fn completes_enum_variant() {
289 check( 233 check(
290 r#" 234 r#"
@@ -749,24 +693,4 @@ fn main() {
749 "#]], 693 "#]],
750 ); 694 );
751 } 695 }
752
753 #[test]
754 fn completes_types_and_const_in_arg_list() {
755 check(
756 r#"
757mod foo {
758 pub const CONST: () = ();
759 pub type Type = ();
760}
761
762struct Foo<T>(t);
763
764fn foo(_: Foo<foo::$0>) {}
765"#,
766 expect![[r#"
767 ta Type
768 ct CONST
769 "#]],
770 );
771 }
772} 696}
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 81c4fb305..380c1e079 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -113,78 +113,6 @@ mod tests {
113 } 113 }
114 114
115 #[test] 115 #[test]
116 fn dont_complete_values_in_type_pos() {
117 check(
118 r#"
119const FOO: () = ();
120static BAR: () = ();
121enum Foo {
122 Bar
123}
124struct Baz;
125fn foo() {
126 let local = ();
127 let _: $0;
128}
129"#,
130 expect![[r#"
131 en Foo
132 st Baz
133 "#]],
134 );
135 }
136
137 #[test]
138 fn bind_pat_and_path_ignore_at() {
139 check(
140 r#"
141enum Enum { A, B }
142fn quux(x: Option<Enum>) {
143 match x {
144 None => (),
145 Some(en$0 @ Enum::A) => (),
146 }
147}
148"#,
149 expect![[r#""#]],
150 );
151 }
152
153 #[test]
154 fn bind_pat_and_path_ignore_ref() {
155 check(
156 r#"
157enum Enum { A, B }
158fn quux(x: Option<Enum>) {
159 match x {
160 None => (),
161 Some(ref en$0) => (),
162 }
163}
164"#,
165 expect![[r#""#]],
166 );
167 }
168
169 #[test]
170 fn bind_pat_and_path() {
171 check(
172 r#"
173enum Enum { A, B }
174fn quux(x: Option<Enum>) {
175 match x {
176 None => (),
177 Some(En$0) => (),
178 }
179}
180"#,
181 expect![[r#"
182 en Enum
183 "#]],
184 );
185 }
186
187 #[test]
188 fn completes_bindings_from_let() { 116 fn completes_bindings_from_let() {
189 check( 117 check(
190 r#" 118 r#"
@@ -289,29 +217,6 @@ fn main() {
289 } 217 }
290 218
291 #[test] 219 #[test]
292 fn completes_generic_params_in_struct() {
293 check(
294 r#"struct S<T> { x: $0}"#,
295 expect![[r#"
296 sp Self
297 tp T
298 st S<…>
299 "#]],
300 );
301 }
302
303 #[test]
304 fn completes_self_in_enum() {
305 check(
306 r#"enum X { Y($0) }"#,
307 expect![[r#"
308 sp Self
309 en X
310 "#]],
311 );
312 }
313
314 #[test]
315 fn completes_module_items() { 220 fn completes_module_items() {
316 check( 221 check(
317 r#" 222 r#"
@@ -365,19 +270,6 @@ mod m {
365 } 270 }
366 271
367 #[test] 272 #[test]
368 fn completes_return_type() {
369 check(
370 r#"
371struct Foo;
372fn x() -> $0
373"#,
374 expect![[r#"
375 st Foo
376 "#]],
377 );
378 }
379
380 #[test]
381 fn dont_show_both_completions_for_shadowing() { 273 fn dont_show_both_completions_for_shadowing() {
382 check( 274 check(
383 r#" 275 r#"
@@ -559,19 +451,6 @@ fn foo() { $0 }
559 } 451 }
560 452
561 #[test] 453 #[test]
562 fn completes_macros_as_type() {
563 check(
564 r#"
565macro_rules! foo { () => {} }
566fn main() { let x: $0 }
567"#,
568 expect![[r#"
569 ma foo!(…) macro_rules! foo
570 "#]],
571 );
572 }
573
574 #[test]
575 fn completes_macros_as_stmt() { 454 fn completes_macros_as_stmt() {
576 check( 455 check(
577 r#" 456 r#"
@@ -716,30 +595,4 @@ fn f() {}
716 expect![[""]], 595 expect![[""]],
717 ) 596 )
718 } 597 }
719
720 #[test]
721 fn completes_types_and_const_in_arg_list() {
722 check(
723 r#"
724enum Bar {
725 Baz
726}
727trait Foo {
728 type Bar;
729}
730
731const CONST: () = ();
732
733fn foo<T: Foo<$0>, const CONST_PARAM: usize>(_: T) {}
734"#,
735 expect![[r#"
736 ta Bar = type Bar;
737 tp T
738 cp CONST_PARAM
739 tt Foo
740 en Bar
741 ct CONST
742 "#]],
743 );
744 }
745} 598}
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index e49e434fa..f0da98739 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -286,8 +286,11 @@ impl<'a> CompletionContext<'a> {
286 ) 286 )
287 } 287 }
288 288
289 pub(crate) fn expect_record_field(&self) -> bool { 289 pub(crate) fn expect_field(&self) -> bool {
290 matches!(self.completion_location, Some(ImmediateLocation::RecordField)) 290 matches!(
291 self.completion_location,
292 Some(ImmediateLocation::RecordField | ImmediateLocation::TupleField)
293 )
291 } 294 }
292 295
293 pub(crate) fn in_use_tree(&self) -> bool { 296 pub(crate) fn in_use_tree(&self) -> bool {
@@ -385,14 +388,19 @@ impl<'a> CompletionContext<'a> {
385 (ty, name) 388 (ty, name)
386 }, 389 },
387 ast::ArgList(_it) => { 390 ast::ArgList(_it) => {
388 cov_mark::hit!(expected_type_fn_param_with_leading_char); 391 cov_mark::hit!(expected_type_fn_param);
389 cov_mark::hit!(expected_type_fn_param_without_leading_char);
390 ActiveParameter::at_token( 392 ActiveParameter::at_token(
391 &self.sema, 393 &self.sema,
392 self.token.clone(), 394 self.token.clone(),
393 ).map(|ap| { 395 ).map(|ap| {
394 let name = ap.ident().map(NameOrNameRef::Name); 396 let name = ap.ident().map(NameOrNameRef::Name);
395 (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)
396 }) 404 })
397 .unwrap_or((None, None)) 405 .unwrap_or((None, None))
398 }, 406 },
@@ -697,6 +705,19 @@ fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
697 use_tree.path().zip(Some(true)) 705 use_tree.path().zip(Some(true))
698} 706}
699 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![&]
719}
720
700#[cfg(test)] 721#[cfg(test)]
701mod tests { 722mod tests {
702 use expect_test::{expect, Expect}; 723 use expect_test::{expect, Expect};
@@ -769,14 +790,18 @@ fn foo() {
769 } 790 }
770 791
771 #[test] 792 #[test]
772 fn expected_type_fn_param_without_leading_char() { 793 fn expected_type_fn_param() {
773 cov_mark::check!(expected_type_fn_param_without_leading_char); 794 cov_mark::check!(expected_type_fn_param);
774 check_expected_type_and_name( 795 check_expected_type_and_name(
775 r#" 796 r#"
776fn foo() { 797fn foo() { bar($0); }
777 bar($0); 798fn bar(x: u32) {}
778} 799"#,
779 800 expect![[r#"ty: u32, name: x"#]],
801 );
802 check_expected_type_and_name(
803 r#"
804fn foo() { bar(c$0); }
780fn bar(x: u32) {} 805fn bar(x: u32) {}
781"#, 806"#,
782 expect![[r#"ty: u32, name: x"#]], 807 expect![[r#"ty: u32, name: x"#]],
@@ -784,18 +809,29 @@ fn bar(x: u32) {}
784 } 809 }
785 810
786 #[test] 811 #[test]
787 fn expected_type_fn_param_with_leading_char() { 812 fn expected_type_fn_param_ref() {
788 cov_mark::check!(expected_type_fn_param_with_leading_char); 813 cov_mark::check!(expected_type_fn_param_ref);
789 check_expected_type_and_name( 814 check_expected_type_and_name(
790 r#" 815 r#"
791fn foo() { 816fn foo() { bar(&$0); }
792 bar(c$0); 817fn bar(x: &u32) {}
793}
794
795fn bar(x: u32) {}
796"#, 818"#,
797 expect![[r#"ty: u32, name: x"#]], 819 expect![[r#"ty: u32, name: x"#]],
798 ); 820 );
821 check_expected_type_and_name(
822 r#"
823fn foo() { bar(&mut $0); }
824fn bar(x: &mut u32) {}
825"#,
826 expect![[r#"ty: u32, name: x"#]],
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 );
799 } 835 }
800 836
801 #[test] 837 #[test]
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 271409c38..757c9a3da 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -31,6 +31,7 @@ pub(crate) enum ImmediateLocation {
31 Impl, 31 Impl,
32 Trait, 32 Trait,
33 RecordField, 33 RecordField,
34 TupleField,
34 RefExpr, 35 RefExpr,
35 IdentPat, 36 IdentPat,
36 BlockExpr, 37 BlockExpr,
@@ -187,7 +188,13 @@ pub(crate) fn determine_location(
187 ast::SourceFile(_it) => ImmediateLocation::ItemList, 188 ast::SourceFile(_it) => ImmediateLocation::ItemList,
188 ast::ItemList(_it) => ImmediateLocation::ItemList, 189 ast::ItemList(_it) => ImmediateLocation::ItemList,
189 ast::RefExpr(_it) => ImmediateLocation::RefExpr, 190 ast::RefExpr(_it) => ImmediateLocation::RefExpr,
190 ast::RecordField(_it) => ImmediateLocation::RecordField, 191 ast::RecordField(it) => if it.ty().map_or(false, |it| it.syntax().text_range().contains(offset)) {
192 return None;
193 } else {
194 ImmediateLocation::RecordField
195 },
196 ast::TupleField(_it) => ImmediateLocation::TupleField,
197 ast::TupleFieldList(_it) => ImmediateLocation::TupleField,
191 ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) { 198 ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) {
192 Some(IMPL) => ImmediateLocation::Impl, 199 Some(IMPL) => ImmediateLocation::Impl,
193 Some(TRAIT) => ImmediateLocation::Trait, 200 Some(TRAIT) => ImmediateLocation::Trait,
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 9bec03e17..1a9b6212a 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -1057,7 +1057,7 @@ fn f() {
1057 #[test] 1057 #[test]
1058 fn suggest_ref_mut() { 1058 fn suggest_ref_mut() {
1059 cov_mark::check!(suggest_ref); 1059 cov_mark::check!(suggest_ref);
1060 check( 1060 check_relevance(
1061 r#" 1061 r#"
1062struct S; 1062struct S;
1063fn foo(s: &mut S) {} 1063fn foo(s: &mut S) {}
@@ -1067,58 +1067,29 @@ fn main() {
1067} 1067}
1068 "#, 1068 "#,
1069 expect![[r#" 1069 expect![[r#"
1070 [ 1070 lc s [name+local]
1071 CompletionItem { 1071 lc &mut s [type+name+local]
1072 label: "S", 1072 st S []
1073 source_range: 70..70, 1073 fn main() []
1074 delete: 70..70, 1074 fn foo(…) []
1075 insert: "S",
1076 kind: SymbolKind(
1077 Struct,
1078 ),
1079 },
1080 CompletionItem {
1081 label: "foo(…)",
1082 source_range: 70..70,
1083 delete: 70..70,
1084 insert: "foo(${1:&mut s})$0",
1085 kind: SymbolKind(
1086 Function,
1087 ),
1088 lookup: "foo",
1089 detail: "fn(&mut S)",
1090 trigger_call_info: true,
1091 },
1092 CompletionItem {
1093 label: "main()",
1094 source_range: 70..70,
1095 delete: 70..70,
1096 insert: "main()$0",
1097 kind: SymbolKind(
1098 Function,
1099 ),
1100 lookup: "main",
1101 detail: "fn()",
1102 },
1103 CompletionItem {
1104 label: "s",
1105 source_range: 70..70,
1106 delete: 70..70,
1107 insert: "s",
1108 kind: SymbolKind(
1109 Local,
1110 ),
1111 detail: "S",
1112 relevance: CompletionRelevance {
1113 exact_name_match: true,
1114 type_match: None,
1115 is_local: true,
1116 },
1117 ref_match: "&mut ",
1118 },
1119 ]
1120 "#]], 1075 "#]],
1121 ) 1076 );
1077 check_relevance(
1078 r#"
1079struct S;
1080fn foo(s: &mut S) {}
1081fn main() {
1082 let mut s = S;
1083 foo(&mut $0);
1084}
1085 "#,
1086 expect![[r#"
1087 lc s [type+name+local]
1088 st S []
1089 fn main() []
1090 fn foo(…) []
1091 "#]],
1092 );
1122 } 1093 }
1123 1094
1124 #[test] 1095 #[test]
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs
index 211c89c40..97298ff27 100644
--- a/crates/ide_completion/src/tests.rs
+++ b/crates/ide_completion/src/tests.rs
@@ -7,6 +7,10 @@
7mod item_list; 7mod item_list;
8mod use_tree; 8mod use_tree;
9mod items; 9mod items;
10mod pattern;
11mod type_pos;
12
13use std::mem;
10 14
11use hir::{PrefixKind, Semantics}; 15use hir::{PrefixKind, Semantics};
12use ide_db::{ 16use ide_db::{
@@ -45,7 +49,16 @@ pub(crate) fn completion_list(code: &str) -> String {
45} 49}
46 50
47fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { 51fn completion_list_with_config(config: CompletionConfig, code: &str) -> String {
48 render_completion_list(get_all_items(config, code)) 52 // filter out all but one builtintype completion for smaller test outputs
53 let items = get_all_items(config, code);
54 let mut bt_seen = false;
55 let items = items
56 .into_iter()
57 .filter(|it| {
58 it.completion_kind != CompletionKind::BuiltinType || !mem::replace(&mut bt_seen, true)
59 })
60 .collect();
61 render_completion_list(items)
49} 62}
50 63
51/// Creates analysis from a multi-file fixture, returns positions marked with $0. 64/// Creates analysis from a multi-file fixture, returns positions marked with $0.
diff --git a/crates/ide_completion/src/tests/items.rs b/crates/ide_completion/src/tests/items.rs
index 8dfb8221b..b98baffd6 100644
--- a/crates/ide_completion/src/tests/items.rs
+++ b/crates/ide_completion/src/tests/items.rs
@@ -35,22 +35,6 @@ impl Tra$0
35 ma foo!(…) #[macro_export] macro_rules! foo 35 ma foo!(…) #[macro_export] macro_rules! foo
36 ma foo!(…) #[macro_export] macro_rules! foo 36 ma foo!(…) #[macro_export] macro_rules! foo
37 bt u32 37 bt u32
38 bt bool
39 bt u8
40 bt isize
41 bt u16
42 bt u64
43 bt u128
44 bt f32
45 bt i128
46 bt i16
47 bt str
48 bt i64
49 bt char
50 bt f64
51 bt i32
52 bt i8
53 bt usize
54 "##]], 38 "##]],
55 ) 39 )
56} 40}
@@ -69,22 +53,6 @@ impl Trait for Str$0
69 ma foo!(…) #[macro_export] macro_rules! foo 53 ma foo!(…) #[macro_export] macro_rules! foo
70 ma foo!(…) #[macro_export] macro_rules! foo 54 ma foo!(…) #[macro_export] macro_rules! foo
71 bt u32 55 bt u32
72 bt bool
73 bt u8
74 bt isize
75 bt u16
76 bt u64
77 bt u128
78 bt f32
79 bt i128
80 bt i16
81 bt str
82 bt i64
83 bt char
84 bt f64
85 bt i32
86 bt i8
87 bt usize
88 "##]], 56 "##]],
89 ) 57 )
90} 58}
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
new file mode 100644
index 000000000..1ad5ccd97
--- /dev/null
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -0,0 +1,348 @@
1//! Completions tests for pattern position.
2use expect_test::{expect, Expect};
3
4use crate::tests::completion_list;
5
6fn check(ra_fixture: &str, expect: Expect) {
7 let actual = completion_list(ra_fixture);
8 expect.assert_eq(&actual)
9}
10
11fn check_with(ra_fixture: &str, expect: Expect) {
12 let base = r#"
13enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
14use self::Enum::TupleV;
15mod module {}
16
17static STATIC: Unit = Unit;
18const CONST: Unit = Unit;
19struct Record { field: u32 }
20struct Tuple(u32);
21struct Unit
22macro_rules! makro {}
23"#;
24 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
25 expect.assert_eq(&actual)
26}
27
28#[test]
29fn ident_rebind_pat() {
30 check(
31 r#"
32fn quux() {
33 let en$0 @ x
34}
35"#,
36 expect![[r#"
37 kw mut
38 "#]],
39 );
40}
41
42#[test]
43fn ident_ref_pat() {
44 check(
45 r#"
46fn quux() {
47 let ref en$0
48}
49"#,
50 expect![[r#"
51 kw mut
52 "#]],
53 );
54 check(
55 r#"
56fn quux() {
57 let ref en$0 @ x
58}
59"#,
60 expect![[r#"
61 kw mut
62 "#]],
63 );
64}
65
66#[test]
67fn ident_ref_mut_pat() {
68 // FIXME mut is already here, don't complete it again
69 check(
70 r#"
71fn quux() {
72 let ref mut en$0
73}
74"#,
75 expect![[r#"
76 kw mut
77 "#]],
78 );
79 check(
80 r#"
81fn quux() {
82 let ref mut en$0 @ x
83}
84"#,
85 expect![[r#"
86 kw mut
87 "#]],
88 );
89}
90
91#[test]
92fn ref_pat() {
93 check(
94 r#"
95fn quux() {
96 let &en$0
97}
98"#,
99 expect![[r#"
100 kw mut
101 "#]],
102 );
103 // FIXME mut is already here, don't complete it again
104 check(
105 r#"
106fn quux() {
107 let &mut en$0
108}
109"#,
110 expect![[r#"
111 kw mut
112 "#]],
113 );
114}
115
116#[test]
117fn refutable() {
118 check_with(
119 r#"
120fn foo() {
121 if let a$0
122}
123"#,
124 expect![[r#"
125 kw mut
126 bn Record Record { field$1 }$0
127 st Record
128 en Enum
129 bn Tuple Tuple($1)$0
130 st Tuple
131 md module
132 bn TupleV TupleV($1)$0
133 ev TupleV
134 st Unit
135 ct CONST
136 ma makro!(…) macro_rules! makro
137 "#]],
138 );
139}
140
141#[test]
142fn irrefutable() {
143 check_with(
144 r#"
145fn foo() {
146 let a$0
147}
148"#,
149 expect![[r#"
150 kw mut
151 bn Record Record { field$1 }$0
152 st Record
153 bn Tuple Tuple($1)$0
154 st Tuple
155 st Unit
156 ma makro!(…) macro_rules! makro
157 "#]],
158 );
159}
160
161#[test]
162fn in_param() {
163 check_with(
164 r#"
165fn foo(a$0) {
166}
167"#,
168 expect![[r#"
169 kw mut
170 bn Record Record { field$1 }: Record$0
171 st Record
172 bn Tuple Tuple($1): Tuple$0
173 st Tuple
174 st Unit
175 ma makro!(…) macro_rules! makro
176 "#]],
177 );
178}
179
180#[test]
181fn only_fn_like_macros() {
182 check(
183 r#"
184macro_rules! m { ($e:expr) => { $e } }
185
186#[rustc_builtin_macro]
187macro Clone {}
188
189fn foo() {
190 let x$0
191}
192"#,
193 expect![[r#"
194 kw mut
195 ma m!(…) macro_rules! m
196 "#]],
197 );
198}
199
200#[test]
201fn in_simple_macro_call() {
202 check(
203 r#"
204macro_rules! m { ($e:expr) => { $e } }
205enum E { X }
206
207fn foo() {
208 m!(match E::X { a$0 })
209}
210"#,
211 expect![[r#"
212 kw mut
213 ev E::X ()
214 en E
215 ma m!(…) macro_rules! m
216 "#]],
217 );
218}
219
220#[test]
221fn omits_private_fields_pat() {
222 check(
223 r#"
224mod foo {
225 pub struct Record { pub field: i32, _field: i32 }
226 pub struct Tuple(pub u32, u32);
227 pub struct Invisible(u32, u32);
228}
229use foo::*;
230
231fn outer() {
232 if let a$0
233}
234"#,
235 expect![[r#"
236 kw mut
237 bn Record Record { field$1, .. }$0
238 st Record
239 bn Tuple Tuple($1, ..)$0
240 st Tuple
241 st Invisible
242 md foo
243 "#]],
244 )
245}
246
247// #[test]
248// fn only_shows_ident_completion() {
249// check_edit(
250// "Foo",
251// r#"
252// struct Foo(i32);
253// fn main() {
254// match Foo(92) {
255// a$0(92) => (),
256// }
257// }
258// "#,
259// r#"
260// struct Foo(i32);
261// fn main() {
262// match Foo(92) {
263// Foo(92) => (),
264// }
265// }
266// "#,
267// );
268// }
269
270#[test]
271fn completes_self_pats() {
272 check(
273 r#"
274struct Foo(i32);
275impl Foo {
276 fn foo() {
277 match Foo(0) {
278 a$0
279 }
280 }
281}
282 "#,
283 expect![[r#"
284 kw mut
285 bn Self Self($1)$0
286 sp Self
287 bn Foo Foo($1)$0
288 st Foo
289 "#]],
290 )
291}
292
293#[test]
294fn completes_qualified_variant() {
295 check(
296 r#"
297enum Foo {
298 Bar { baz: i32 }
299}
300impl Foo {
301 fn foo() {
302 match {Foo::Bar { baz: 0 }} {
303 B$0
304 }
305 }
306}
307 "#,
308 expect![[r#"
309 kw mut
310 bn Self::Bar Self::Bar { baz$1 }$0
311 ev Self::Bar { baz: i32 }
312 bn Foo::Bar Foo::Bar { baz$1 }$0
313 ev Foo::Bar { baz: i32 }
314 sp Self
315 en Foo
316 "#]],
317 )
318}
319
320#[test]
321fn completes_in_record_field_pat() {
322 check(
323 r#"
324struct Foo { bar: Bar }
325struct Bar(u32);
326fn outer(Foo { bar: $0 }: Foo) {}
327"#,
328 expect![[r#"
329 kw mut
330 bn Foo Foo { bar$1 }$0
331 st Foo
332 bn Bar Bar($1)$0
333 st Bar
334 "#]],
335 )
336}
337
338#[test]
339fn skips_in_record_field_pat_name() {
340 check(
341 r#"
342struct Foo { bar: Bar }
343struct Bar(u32);
344fn outer(Foo { bar$0 }: Foo) {}
345"#,
346 expect![[r#""#]],
347 )
348}
diff --git a/crates/ide_completion/src/tests/type_pos.rs b/crates/ide_completion/src/tests/type_pos.rs
new file mode 100644
index 000000000..1ab47b27e
--- /dev/null
+++ b/crates/ide_completion/src/tests/type_pos.rs
@@ -0,0 +1,177 @@
1//! Completions tests for type position.
2use expect_test::{expect, Expect};
3
4use crate::tests::completion_list;
5
6fn check_with(ra_fixture: &str, expect: Expect) {
7 let base = r#"
8enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
9use self::Enum::TupleV;
10mod module {}
11
12trait Trait {}
13static STATIC: Unit = Unit;
14const CONST: Unit = Unit;
15struct Record { field: u32 }
16struct Tuple(u32);
17struct Unit
18macro_rules! makro {}
19"#;
20 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
21 expect.assert_eq(&actual)
22}
23
24#[test]
25fn record_field_ty() {
26 check_with(
27 r#"
28struct Foo<'lt, T, const C: usize> {
29 f: $0
30}
31"#,
32 expect![[r#"
33 sp Self
34 tp T
35 tt Trait
36 en Enum
37 st Record
38 st Tuple
39 md module
40 st Foo<…>
41 st Unit
42 ma makro!(…) macro_rules! makro
43 bt u32
44 "#]],
45 )
46}
47
48#[test]
49fn tuple_struct_field() {
50 check_with(
51 r#"
52struct Foo<'lt, T, const C: usize>(f$0);
53"#,
54 expect![[r#"
55 kw pub(crate)
56 kw pub
57 sp Self
58 tp T
59 tt Trait
60 en Enum
61 st Record
62 st Tuple
63 md module
64 st Foo<…>
65 st Unit
66 ma makro!(…) macro_rules! makro
67 bt u32
68 "#]],
69 )
70}
71
72#[test]
73fn fn_return_type() {
74 check_with(
75 r#"
76fn x<'lt, T, const C: usize>() -> $0
77"#,
78 expect![[r#"
79 tp T
80 tt Trait
81 en Enum
82 st Record
83 st Tuple
84 md module
85 st Unit
86 ma makro!(…) macro_rules! makro
87 bt u32
88 "#]],
89 );
90}
91
92#[test]
93fn body_type_pos() {
94 check_with(
95 r#"
96fn foo<'lt, T, const C: usize>() {
97 let local = ();
98 let _: $0;
99}
100"#,
101 expect![[r#"
102 tp T
103 tt Trait
104 en Enum
105 st Record
106 st Tuple
107 md module
108 st Unit
109 ma makro!(…) macro_rules! makro
110 bt u32
111 "#]],
112 );
113 check_with(
114 r#"
115fn foo<'lt, T, const C: usize>() {
116 let local = ();
117 let _: self::$0;
118}
119"#,
120 expect![[r#"
121 tt Trait
122 en Enum
123 st Record
124 st Tuple
125 md module
126 st Unit
127 "#]],
128 );
129}
130
131#[test]
132fn completes_types_and_const_in_arg_list() {
133 // FIXME: we should complete the lifetime here for now
134 check_with(
135 r#"
136trait Trait2 {
137 type Foo;
138}
139
140fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
141"#,
142 expect![[r#"
143 ta Foo = type Foo;
144 tp T
145 cp CONST_PARAM
146 tt Trait
147 en Enum
148 st Record
149 st Tuple
150 tt Trait2
151 md module
152 st Unit
153 ct CONST
154 ma makro!(…) macro_rules! makro
155 bt u32
156 "#]],
157 );
158 check_with(
159 r#"
160trait Trait2 {
161 type Foo;
162}
163
164fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
165 "#,
166 expect![[r#"
167 tt Trait
168 en Enum
169 st Record
170 st Tuple
171 tt Trait2
172 md module
173 st Unit
174 ct CONST
175 "#]],
176 );
177}