aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/completion/complete_unqualified_path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/completion/complete_unqualified_path.rs')
-rw-r--r--crates/ide/src/completion/complete_unqualified_path.rs658
1 files changed, 658 insertions, 0 deletions
diff --git a/crates/ide/src/completion/complete_unqualified_path.rs b/crates/ide/src/completion/complete_unqualified_path.rs
new file mode 100644
index 000000000..824227f31
--- /dev/null
+++ b/crates/ide/src/completion/complete_unqualified_path.rs
@@ -0,0 +1,658 @@
1//! Completion of names from the current scope, e.g. locals and imported items.
2
3use hir::{Adt, ModuleDef, ScopeDef, Type};
4use syntax::AstNode;
5use test_utils::mark;
6
7use crate::completion::{CompletionContext, Completions};
8
9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
11 return;
12 }
13 if ctx.record_lit_syntax.is_some()
14 || ctx.record_pat_syntax.is_some()
15 || ctx.attribute_under_caret.is_some()
16 {
17 return;
18 }
19
20 if let Some(ty) = &ctx.expected_type {
21 complete_enum_variants(acc, ctx, ty);
22 }
23
24 if ctx.is_pat_binding_or_const {
25 return;
26 }
27
28 ctx.scope.process_all_names(&mut |name, res| {
29 if ctx.use_item_syntax.is_some() {
30 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
31 if name_ref.syntax().text() == name.to_string().as_str() {
32 mark::hit!(self_fulfilling_completion);
33 return;
34 }
35 }
36 }
37 acc.add_resolution(ctx, name.to_string(), &res)
38 });
39}
40
41fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) {
42 if let Some(Adt::Enum(enum_data)) = ty.as_adt() {
43 let variants = enum_data.variants(ctx.db);
44
45 let module = if let Some(module) = ctx.scope.module() {
46 // Compute path from the completion site if available.
47 module
48 } else {
49 // Otherwise fall back to the enum's definition site.
50 enum_data.module(ctx.db)
51 };
52
53 for variant in variants {
54 if let Some(path) = module.find_use_path(ctx.db, ModuleDef::from(variant)) {
55 // Variants with trivial paths are already added by the existing completion logic,
56 // so we should avoid adding these twice
57 if path.segments.len() > 1 {
58 acc.add_qualified_enum_variant(ctx, variant, path);
59 }
60 }
61 }
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use expect::{expect, Expect};
68 use test_utils::mark;
69
70 use crate::completion::{
71 test_utils::{check_edit, completion_list},
72 CompletionKind,
73 };
74
75 fn check(ra_fixture: &str, expect: Expect) {
76 let actual = completion_list(ra_fixture, CompletionKind::Reference);
77 expect.assert_eq(&actual)
78 }
79
80 #[test]
81 fn self_fulfilling_completion() {
82 mark::check!(self_fulfilling_completion);
83 check(
84 r#"
85use foo<|>
86use std::collections;
87"#,
88 expect![[r#"
89 ?? collections
90 "#]],
91 );
92 }
93
94 #[test]
95 fn bind_pat_and_path_ignore_at() {
96 check(
97 r#"
98enum Enum { A, B }
99fn quux(x: Option<Enum>) {
100 match x {
101 None => (),
102 Some(en<|> @ Enum::A) => (),
103 }
104}
105"#,
106 expect![[""]],
107 );
108 }
109
110 #[test]
111 fn bind_pat_and_path_ignore_ref() {
112 check(
113 r#"
114enum Enum { A, B }
115fn quux(x: Option<Enum>) {
116 match x {
117 None => (),
118 Some(ref en<|>) => (),
119 }
120}
121"#,
122 expect![[""]],
123 );
124 }
125
126 #[test]
127 fn bind_pat_and_path() {
128 check(
129 r#"
130enum Enum { A, B }
131fn quux(x: Option<Enum>) {
132 match x {
133 None => (),
134 Some(En<|>) => (),
135 }
136}
137"#,
138 expect![[r#"
139 en Enum
140 "#]],
141 );
142 }
143
144 #[test]
145 fn completes_bindings_from_let() {
146 check(
147 r#"
148fn quux(x: i32) {
149 let y = 92;
150 1 + <|>;
151 let z = ();
152}
153"#,
154 expect![[r#"
155 fn quux(…) fn quux(x: i32)
156 bn x i32
157 bn y i32
158 "#]],
159 );
160 }
161
162 #[test]
163 fn completes_bindings_from_if_let() {
164 check(
165 r#"
166fn quux() {
167 if let Some(x) = foo() {
168 let y = 92;
169 };
170 if let Some(a) = bar() {
171 let b = 62;
172 1 + <|>
173 }
174}
175"#,
176 expect![[r#"
177 bn a
178 bn b i32
179 fn quux() fn quux()
180 "#]],
181 );
182 }
183
184 #[test]
185 fn completes_bindings_from_for() {
186 check(
187 r#"
188fn quux() {
189 for x in &[1, 2, 3] { <|> }
190}
191"#,
192 expect![[r#"
193 fn quux() fn quux()
194 bn x
195 "#]],
196 );
197 }
198
199 #[test]
200 fn completes_if_prefix_is_keyword() {
201 mark::check!(completes_if_prefix_is_keyword);
202 check_edit(
203 "wherewolf",
204 r#"
205fn main() {
206 let wherewolf = 92;
207 drop(where<|>)
208}
209"#,
210 r#"
211fn main() {
212 let wherewolf = 92;
213 drop(wherewolf)
214}
215"#,
216 )
217 }
218
219 #[test]
220 fn completes_generic_params() {
221 check(
222 r#"fn quux<T>() { <|> }"#,
223 expect![[r#"
224 tp T
225 fn quux() fn quux<T>()
226 "#]],
227 );
228 }
229
230 #[test]
231 fn completes_generic_params_in_struct() {
232 check(
233 r#"struct S<T> { x: <|>}"#,
234 expect![[r#"
235 st S<…>
236 tp Self
237 tp T
238 "#]],
239 );
240 }
241
242 #[test]
243 fn completes_self_in_enum() {
244 check(
245 r#"enum X { Y(<|>) }"#,
246 expect![[r#"
247 tp Self
248 en X
249 "#]],
250 );
251 }
252
253 #[test]
254 fn completes_module_items() {
255 check(
256 r#"
257struct S;
258enum E {}
259fn quux() { <|> }
260"#,
261 expect![[r#"
262 en E
263 st S
264 fn quux() fn quux()
265 "#]],
266 );
267 }
268
269 #[test]
270 fn completes_extern_prelude() {
271 check(
272 r#"
273//- /lib.rs
274use <|>;
275
276//- /other_crate/lib.rs
277// nothing here
278"#,
279 expect![[r#"
280 md other_crate
281 "#]],
282 );
283 }
284
285 #[test]
286 fn completes_module_items_in_nested_modules() {
287 check(
288 r#"
289struct Foo;
290mod m {
291 struct Bar;
292 fn quux() { <|> }
293}
294"#,
295 expect![[r#"
296 st Bar
297 fn quux() fn quux()
298 "#]],
299 );
300 }
301
302 #[test]
303 fn completes_return_type() {
304 check(
305 r#"
306struct Foo;
307fn x() -> <|>
308"#,
309 expect![[r#"
310 st Foo
311 fn x() fn x()
312 "#]],
313 );
314 }
315
316 #[test]
317 fn dont_show_both_completions_for_shadowing() {
318 check(
319 r#"
320fn foo() {
321 let bar = 92;
322 {
323 let bar = 62;
324 drop(<|>)
325 }
326}
327"#,
328 // FIXME: should be only one bar here
329 expect![[r#"
330 bn bar i32
331 bn bar i32
332 fn foo() fn foo()
333 "#]],
334 );
335 }
336
337 #[test]
338 fn completes_self_in_methods() {
339 check(
340 r#"impl S { fn foo(&self) { <|> } }"#,
341 expect![[r#"
342 tp Self
343 bn self &{unknown}
344 "#]],
345 );
346 }
347
348 #[test]
349 fn completes_prelude() {
350 check(
351 r#"
352//- /main.rs
353fn foo() { let x: <|> }
354
355//- /std/lib.rs
356#[prelude_import]
357use prelude::*;
358
359mod prelude { struct Option; }
360"#,
361 expect![[r#"
362 st Option
363 fn foo() fn foo()
364 md std
365 "#]],
366 );
367 }
368
369 #[test]
370 fn completes_std_prelude_if_core_is_defined() {
371 check(
372 r#"
373//- /main.rs
374fn foo() { let x: <|> }
375
376//- /core/lib.rs
377#[prelude_import]
378use prelude::*;
379
380mod prelude { struct Option; }
381
382//- /std/lib.rs
383#[prelude_import]
384use prelude::*;
385
386mod prelude { struct String; }
387"#,
388 expect![[r#"
389 st String
390 md core
391 fn foo() fn foo()
392 md std
393 "#]],
394 );
395 }
396
397 #[test]
398 fn completes_macros_as_value() {
399 check(
400 r#"
401macro_rules! foo { () => {} }
402
403#[macro_use]
404mod m1 {
405 macro_rules! bar { () => {} }
406}
407
408mod m2 {
409 macro_rules! nope { () => {} }
410
411 #[macro_export]
412 macro_rules! baz { () => {} }
413}
414
415fn main() { let v = <|> }
416"#,
417 expect![[r##"
418 ma bar!(…) macro_rules! bar
419 ma baz!(…) #[macro_export]
420 macro_rules! baz
421 ma foo!(…) macro_rules! foo
422 md m1
423 md m2
424 fn main() fn main()
425 "##]],
426 );
427 }
428
429 #[test]
430 fn completes_both_macro_and_value() {
431 check(
432 r#"
433macro_rules! foo { () => {} }
434fn foo() { <|> }
435"#,
436 expect![[r#"
437 ma foo!(…) macro_rules! foo
438 fn foo() fn foo()
439 "#]],
440 );
441 }
442
443 #[test]
444 fn completes_macros_as_type() {
445 check(
446 r#"
447macro_rules! foo { () => {} }
448fn main() { let x: <|> }
449"#,
450 expect![[r#"
451 ma foo!(…) macro_rules! foo
452 fn main() fn main()
453 "#]],
454 );
455 }
456
457 #[test]
458 fn completes_macros_as_stmt() {
459 check(
460 r#"
461macro_rules! foo { () => {} }
462fn main() { <|> }
463"#,
464 expect![[r#"
465 ma foo!(…) macro_rules! foo
466 fn main() fn main()
467 "#]],
468 );
469 }
470
471 #[test]
472 fn completes_local_item() {
473 check(
474 r#"
475fn main() {
476 return f<|>;
477 fn frobnicate() {}
478}
479"#,
480 expect![[r#"
481 fn frobnicate() fn frobnicate()
482 fn main() fn main()
483 "#]],
484 );
485 }
486
487 #[test]
488 fn completes_in_simple_macro_1() {
489 check(
490 r#"
491macro_rules! m { ($e:expr) => { $e } }
492fn quux(x: i32) {
493 let y = 92;
494 m!(<|>);
495}
496"#,
497 expect![[r#"
498 ma m!(…) macro_rules! m
499 fn quux(…) fn quux(x: i32)
500 bn x i32
501 bn y i32
502 "#]],
503 );
504 }
505
506 #[test]
507 fn completes_in_simple_macro_2() {
508 check(
509 r"
510macro_rules! m { ($e:expr) => { $e } }
511fn quux(x: i32) {
512 let y = 92;
513 m!(x<|>);
514}
515",
516 expect![[r#"
517 ma m!(…) macro_rules! m
518 fn quux(…) fn quux(x: i32)
519 bn x i32
520 bn y i32
521 "#]],
522 );
523 }
524
525 #[test]
526 fn completes_in_simple_macro_without_closing_parens() {
527 check(
528 r#"
529macro_rules! m { ($e:expr) => { $e } }
530fn quux(x: i32) {
531 let y = 92;
532 m!(x<|>
533}
534"#,
535 expect![[r#"
536 ma m!(…) macro_rules! m
537 fn quux(…) fn quux(x: i32)
538 bn x i32
539 bn y i32
540 "#]],
541 );
542 }
543
544 #[test]
545 fn completes_unresolved_uses() {
546 check(
547 r#"
548use spam::Quux;
549
550fn main() { <|> }
551"#,
552 expect![[r#"
553 ?? Quux
554 fn main() fn main()
555 "#]],
556 );
557 }
558 #[test]
559 fn completes_enum_variant_matcharm() {
560 check(
561 r#"
562enum Foo { Bar, Baz, Quux }
563
564fn main() {
565 let foo = Foo::Quux;
566 match foo { Qu<|> }
567}
568"#,
569 expect![[r#"
570 en Foo
571 ev Foo::Bar ()
572 ev Foo::Baz ()
573 ev Foo::Quux ()
574 "#]],
575 )
576 }
577
578 #[test]
579 fn completes_enum_variant_iflet() {
580 check(
581 r#"
582enum Foo { Bar, Baz, Quux }
583
584fn main() {
585 let foo = Foo::Quux;
586 if let Qu<|> = foo { }
587}
588"#,
589 expect![[r#"
590 en Foo
591 ev Foo::Bar ()
592 ev Foo::Baz ()
593 ev Foo::Quux ()
594 "#]],
595 )
596 }
597
598 #[test]
599 fn completes_enum_variant_basic_expr() {
600 check(
601 r#"
602enum Foo { Bar, Baz, Quux }
603fn main() { let foo: Foo = Q<|> }
604"#,
605 expect![[r#"
606 en Foo
607 ev Foo::Bar ()
608 ev Foo::Baz ()
609 ev Foo::Quux ()
610 fn main() fn main()
611 "#]],
612 )
613 }
614
615 #[test]
616 fn completes_enum_variant_from_module() {
617 check(
618 r#"
619mod m { pub enum E { V } }
620fn f() -> m::E { V<|> }
621"#,
622 expect![[r#"
623 fn f() fn f() -> m::E
624 md m
625 ev m::E::V ()
626 "#]],
627 )
628 }
629
630 #[test]
631 fn dont_complete_attr() {
632 check(
633 r#"
634struct Foo;
635#[<|>]
636fn f() {}
637"#,
638 expect![[""]],
639 )
640 }
641
642 #[test]
643 fn completes_type_or_trait_in_impl_block() {
644 check(
645 r#"
646trait MyTrait {}
647struct MyStruct {}
648
649impl My<|>
650"#,
651 expect![[r#"
652 st MyStruct
653 tt MyTrait
654 tp Self
655 "#]],
656 )
657 }
658}