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