aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/complete_path.rs
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-11-28 07:19:14 +0000
committerSeivan Heidari <[email protected]>2019-11-28 07:19:14 +0000
commit18a0937585b836ec5ed054b9ae48e0156ab6d9ef (patch)
tree9de2c0267ddcc00df717f90034d0843d751a851b /crates/ra_ide/src/completion/complete_path.rs
parenta7394b44c870f585eacfeb3036a33471aff49ff8 (diff)
parent484acc8a61d599662ed63a4cbda091d38a982551 (diff)
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates/ra_ide/src/completion/complete_path.rs')
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs785
1 files changed, 785 insertions, 0 deletions
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
new file mode 100644
index 000000000..89e0009a1
--- /dev/null
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -0,0 +1,785 @@
1//! FIXME: write short doc here
2
3use hir::{Adt, Either, HasSource, PathResolution};
4use ra_syntax::AstNode;
5use test_utils::tested_by;
6
7use crate::completion::{CompletionContext, Completions};
8
9pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
10 let path = match &ctx.path_prefix {
11 Some(path) => path.clone(),
12 _ => return,
13 };
14 let def = match ctx.analyzer.resolve_hir_path(ctx.db, &path) {
15 Some(PathResolution::Def(def)) => def,
16 _ => return,
17 };
18 match def {
19 hir::ModuleDef::Module(module) => {
20 let module_scope = module.scope(ctx.db);
21 for (name, def, import) in module_scope {
22 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
23 if ctx.use_item_syntax.is_some() {
24 tested_by!(dont_complete_primitive_in_use);
25 continue;
26 }
27 }
28 if Some(module) == ctx.module {
29 if let Some(import) = import {
30 if let Either::A(use_tree) = import.source(ctx.db).value {
31 if use_tree.syntax().text_range().contains_inclusive(ctx.offset) {
32 // for `use self::foo<|>`, don't suggest `foo` as a completion
33 tested_by!(dont_complete_current_use);
34 continue;
35 }
36 }
37 }
38 }
39 acc.add_resolution(ctx, name.to_string(), &def);
40 }
41 }
42 hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => {
43 if let hir::ModuleDef::Adt(Adt::Enum(e)) = def {
44 for variant in e.variants(ctx.db) {
45 acc.add_enum_variant(ctx, variant);
46 }
47 }
48 let ty = match def {
49 hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
50 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
51 _ => unreachable!(),
52 };
53 ctx.analyzer.iterate_path_candidates(ctx.db, &ty, None, |_ty, item| {
54 match item {
55 hir::AssocItem::Function(func) => {
56 if !func.has_self_param(ctx.db) {
57 acc.add_function(ctx, func);
58 }
59 }
60 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
61 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
62 }
63 None::<()>
64 });
65 // Iterate assoc types separately
66 // FIXME: complete T::AssocType
67 let krate = ctx.module.map(|m| m.krate());
68 if let Some(krate) = krate {
69 ty.iterate_impl_items(ctx.db, krate, |item| {
70 match item {
71 hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {}
72 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
73 }
74 None::<()>
75 });
76 }
77 }
78 hir::ModuleDef::Trait(t) => {
79 for item in t.items(ctx.db) {
80 match item {
81 hir::AssocItem::Function(func) => {
82 if !func.has_self_param(ctx.db) {
83 acc.add_function(ctx, func);
84 }
85 }
86 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
87 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
88 }
89 }
90 }
91 _ => {}
92 };
93}
94
95#[cfg(test)]
96mod tests {
97 use test_utils::covers;
98
99 use crate::completion::{do_completion, CompletionItem, CompletionKind};
100 use insta::assert_debug_snapshot;
101
102 fn do_reference_completion(code: &str) -> Vec<CompletionItem> {
103 do_completion(code, CompletionKind::Reference)
104 }
105
106 #[test]
107 fn dont_complete_current_use() {
108 covers!(dont_complete_current_use);
109 let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference);
110 assert!(completions.is_empty());
111 }
112
113 #[test]
114 fn dont_complete_current_use_in_braces_with_glob() {
115 let completions = do_completion(
116 r"
117 mod foo { pub struct S; }
118 use self::{foo::*, bar<|>};
119 ",
120 CompletionKind::Reference,
121 );
122 assert_eq!(completions.len(), 2);
123 }
124
125 #[test]
126 fn dont_complete_primitive_in_use() {
127 covers!(dont_complete_primitive_in_use);
128 let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType);
129 assert!(completions.is_empty());
130 }
131
132 #[test]
133 fn completes_primitives() {
134 let completions =
135 do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType);
136 assert_eq!(completions.len(), 17);
137 }
138
139 #[test]
140 fn completes_mod_with_docs() {
141 assert_debug_snapshot!(
142 do_reference_completion(
143 r"
144 use self::my<|>;
145
146 /// Some simple
147 /// docs describing `mod my`.
148 mod my {
149 struct Bar;
150 }
151 "
152 ),
153 @r###"
154 [
155 CompletionItem {
156 label: "my",
157 source_range: [27; 29),
158 delete: [27; 29),
159 insert: "my",
160 kind: Module,
161 documentation: Documentation(
162 "Some simple\ndocs describing `mod my`.",
163 ),
164 },
165 ]
166 "###
167 );
168 }
169
170 #[test]
171 fn completes_use_item_starting_with_self() {
172 assert_debug_snapshot!(
173 do_reference_completion(
174 r"
175 use self::m::<|>;
176
177 mod m {
178 struct Bar;
179 }
180 "
181 ),
182 @r###"
183 [
184 CompletionItem {
185 label: "Bar",
186 source_range: [30; 30),
187 delete: [30; 30),
188 insert: "Bar",
189 kind: Struct,
190 },
191 ]
192 "###
193 );
194 }
195
196 #[test]
197 fn completes_use_item_starting_with_crate() {
198 assert_debug_snapshot!(
199 do_reference_completion(
200 "
201 //- /lib.rs
202 mod foo;
203 struct Spam;
204 //- /foo.rs
205 use crate::Sp<|>
206 "
207 ),
208 @r###"
209 [
210 CompletionItem {
211 label: "Spam",
212 source_range: [11; 13),
213 delete: [11; 13),
214 insert: "Spam",
215 kind: Struct,
216 },
217 CompletionItem {
218 label: "foo",
219 source_range: [11; 13),
220 delete: [11; 13),
221 insert: "foo",
222 kind: Module,
223 },
224 ]
225 "###
226 );
227 }
228
229 #[test]
230 fn completes_nested_use_tree() {
231 assert_debug_snapshot!(
232 do_reference_completion(
233 "
234 //- /lib.rs
235 mod foo;
236 struct Spam;
237 //- /foo.rs
238 use crate::{Sp<|>};
239 "
240 ),
241 @r###"
242 [
243 CompletionItem {
244 label: "Spam",
245 source_range: [12; 14),
246 delete: [12; 14),
247 insert: "Spam",
248 kind: Struct,
249 },
250 CompletionItem {
251 label: "foo",
252 source_range: [12; 14),
253 delete: [12; 14),
254 insert: "foo",
255 kind: Module,
256 },
257 ]
258 "###
259 );
260 }
261
262 #[test]
263 fn completes_deeply_nested_use_tree() {
264 assert_debug_snapshot!(
265 do_reference_completion(
266 "
267 //- /lib.rs
268 mod foo;
269 pub mod bar {
270 pub mod baz {
271 pub struct Spam;
272 }
273 }
274 //- /foo.rs
275 use crate::{bar::{baz::Sp<|>}};
276 "
277 ),
278 @r###"
279 [
280 CompletionItem {
281 label: "Spam",
282 source_range: [23; 25),
283 delete: [23; 25),
284 insert: "Spam",
285 kind: Struct,
286 },
287 ]
288 "###
289 );
290 }
291
292 #[test]
293 fn completes_enum_variant() {
294 assert_debug_snapshot!(
295 do_reference_completion(
296 "
297 //- /lib.rs
298 /// An enum
299 enum E {
300 /// Foo Variant
301 Foo,
302 /// Bar Variant with i32
303 Bar(i32)
304 }
305 fn foo() { let _ = E::<|> }
306 "
307 ),
308 @r###"
309 [
310 CompletionItem {
311 label: "Bar",
312 source_range: [116; 116),
313 delete: [116; 116),
314 insert: "Bar",
315 kind: EnumVariant,
316 detail: "(i32)",
317 documentation: Documentation(
318 "Bar Variant with i32",
319 ),
320 },
321 CompletionItem {
322 label: "Foo",
323 source_range: [116; 116),
324 delete: [116; 116),
325 insert: "Foo",
326 kind: EnumVariant,
327 detail: "()",
328 documentation: Documentation(
329 "Foo Variant",
330 ),
331 },
332 ]
333 "###
334 );
335 }
336
337 #[test]
338 fn completes_enum_variant_with_details() {
339 assert_debug_snapshot!(
340 do_reference_completion(
341 "
342 //- /lib.rs
343 struct S { field: u32 }
344 /// An enum
345 enum E {
346 /// Foo Variant (empty)
347 Foo,
348 /// Bar Variant with i32 and u32
349 Bar(i32, u32),
350 ///
351 S(S),
352 }
353 fn foo() { let _ = E::<|> }
354 "
355 ),
356 @r###"
357 [
358 CompletionItem {
359 label: "Bar",
360 source_range: [180; 180),
361 delete: [180; 180),
362 insert: "Bar",
363 kind: EnumVariant,
364 detail: "(i32, u32)",
365 documentation: Documentation(
366 "Bar Variant with i32 and u32",
367 ),
368 },
369 CompletionItem {
370 label: "Foo",
371 source_range: [180; 180),
372 delete: [180; 180),
373 insert: "Foo",
374 kind: EnumVariant,
375 detail: "()",
376 documentation: Documentation(
377 "Foo Variant (empty)",
378 ),
379 },
380 CompletionItem {
381 label: "S",
382 source_range: [180; 180),
383 delete: [180; 180),
384 insert: "S",
385 kind: EnumVariant,
386 detail: "(S)",
387 documentation: Documentation(
388 "",
389 ),
390 },
391 ]
392 "###
393 );
394 }
395
396 #[test]
397 fn completes_struct_associated_method() {
398 assert_debug_snapshot!(
399 do_reference_completion(
400 "
401 //- /lib.rs
402 /// A Struct
403 struct S;
404
405 impl S {
406 /// An associated method
407 fn m() { }
408 }
409
410 fn foo() { let _ = S::<|> }
411 "
412 ),
413 @r###"
414 [
415 CompletionItem {
416 label: "m()",
417 source_range: [100; 100),
418 delete: [100; 100),
419 insert: "m()$0",
420 kind: Function,
421 lookup: "m",
422 detail: "fn m()",
423 documentation: Documentation(
424 "An associated method",
425 ),
426 },
427 ]
428 "###
429 );
430 }
431
432 #[test]
433 fn completes_struct_associated_const() {
434 assert_debug_snapshot!(
435 do_reference_completion(
436 "
437 //- /lib.rs
438 /// A Struct
439 struct S;
440
441 impl S {
442 /// An associated const
443 const C: i32 = 42;
444 }
445
446 fn foo() { let _ = S::<|> }
447 "
448 ),
449 @r###"
450 [
451 CompletionItem {
452 label: "C",
453 source_range: [107; 107),
454 delete: [107; 107),
455 insert: "C",
456 kind: Const,
457 detail: "const C: i32 = 42;",
458 documentation: Documentation(
459 "An associated const",
460 ),
461 },
462 ]
463 "###
464 );
465 }
466
467 #[test]
468 fn completes_struct_associated_type() {
469 assert_debug_snapshot!(
470 do_reference_completion(
471 "
472 //- /lib.rs
473 /// A Struct
474 struct S;
475
476 impl S {
477 /// An associated type
478 type T = i32;
479 }
480
481 fn foo() { let _ = S::<|> }
482 "
483 ),
484 @r###"
485 [
486 CompletionItem {
487 label: "T",
488 source_range: [101; 101),
489 delete: [101; 101),
490 insert: "T",
491 kind: TypeAlias,
492 detail: "type T = i32;",
493 documentation: Documentation(
494 "An associated type",
495 ),
496 },
497 ]
498 "###
499 );
500 }
501
502 #[test]
503 fn completes_enum_associated_method() {
504 assert_debug_snapshot!(
505 do_reference_completion(
506 "
507 //- /lib.rs
508 /// An enum
509 enum S {};
510
511 impl S {
512 /// An associated method
513 fn m() { }
514 }
515
516 fn foo() { let _ = S::<|> }
517 "
518 ),
519 @r###"
520 [
521 CompletionItem {
522 label: "m()",
523 source_range: [100; 100),
524 delete: [100; 100),
525 insert: "m()$0",
526 kind: Function,
527 lookup: "m",
528 detail: "fn m()",
529 documentation: Documentation(
530 "An associated method",
531 ),
532 },
533 ]
534 "###
535 );
536 }
537
538 #[test]
539 fn completes_union_associated_method() {
540 assert_debug_snapshot!(
541 do_reference_completion(
542 "
543 //- /lib.rs
544 /// A union
545 union U {};
546
547 impl U {
548 /// An associated method
549 fn m() { }
550 }
551
552 fn foo() { let _ = U::<|> }
553 "
554 ),
555 @r###"
556 [
557 CompletionItem {
558 label: "m()",
559 source_range: [101; 101),
560 delete: [101; 101),
561 insert: "m()$0",
562 kind: Function,
563 lookup: "m",
564 detail: "fn m()",
565 documentation: Documentation(
566 "An associated method",
567 ),
568 },
569 ]
570 "###
571 );
572 }
573
574 #[test]
575 fn completes_use_paths_across_crates() {
576 assert_debug_snapshot!(
577 do_reference_completion(
578 "
579 //- /main.rs
580 use foo::<|>;
581
582 //- /foo/lib.rs
583 pub mod bar {
584 pub struct S;
585 }
586 "
587 ),
588 @r###"
589 [
590 CompletionItem {
591 label: "bar",
592 source_range: [9; 9),
593 delete: [9; 9),
594 insert: "bar",
595 kind: Module,
596 },
597 ]
598 "###
599 );
600 }
601
602 #[test]
603 fn completes_trait_associated_method_1() {
604 assert_debug_snapshot!(
605 do_reference_completion(
606 "
607 //- /lib.rs
608 trait Trait {
609 /// A trait method
610 fn m();
611 }
612
613 fn foo() { let _ = Trait::<|> }
614 "
615 ),
616 @r###"
617 [
618 CompletionItem {
619 label: "m()",
620 source_range: [73; 73),
621 delete: [73; 73),
622 insert: "m()$0",
623 kind: Function,
624 lookup: "m",
625 detail: "fn m()",
626 documentation: Documentation(
627 "A trait method",
628 ),
629 },
630 ]
631 "###
632 );
633 }
634
635 #[test]
636 fn completes_trait_associated_method_2() {
637 assert_debug_snapshot!(
638 do_reference_completion(
639 "
640 //- /lib.rs
641 trait Trait {
642 /// A trait method
643 fn m();
644 }
645
646 struct S;
647 impl Trait for S {}
648
649 fn foo() { let _ = S::<|> }
650 "
651 ),
652 @r###"
653 [
654 CompletionItem {
655 label: "m()",
656 source_range: [99; 99),
657 delete: [99; 99),
658 insert: "m()$0",
659 kind: Function,
660 lookup: "m",
661 detail: "fn m()",
662 documentation: Documentation(
663 "A trait method",
664 ),
665 },
666 ]
667 "###
668 );
669 }
670
671 #[test]
672 fn completes_trait_associated_method_3() {
673 assert_debug_snapshot!(
674 do_reference_completion(
675 "
676 //- /lib.rs
677 trait Trait {
678 /// A trait method
679 fn m();
680 }
681
682 struct S;
683 impl Trait for S {}
684
685 fn foo() { let _ = <S as Trait>::<|> }
686 "
687 ),
688 @r###"
689 [
690 CompletionItem {
691 label: "m()",
692 source_range: [110; 110),
693 delete: [110; 110),
694 insert: "m()$0",
695 kind: Function,
696 lookup: "m",
697 detail: "fn m()",
698 documentation: Documentation(
699 "A trait method",
700 ),
701 },
702 ]
703 "###
704 );
705 }
706
707 #[test]
708 fn completes_type_alias() {
709 assert_debug_snapshot!(
710 do_reference_completion(
711 "
712 struct S;
713 impl S { fn foo() {} }
714 type T = S;
715 impl T { fn bar() {} }
716
717 fn main() {
718 T::<|>;
719 }
720 "
721 ),
722 @r###"
723 [
724 CompletionItem {
725 label: "bar()",
726 source_range: [185; 185),
727 delete: [185; 185),
728 insert: "bar()$0",
729 kind: Function,
730 lookup: "bar",
731 detail: "fn bar()",
732 },
733 CompletionItem {
734 label: "foo()",
735 source_range: [185; 185),
736 delete: [185; 185),
737 insert: "foo()$0",
738 kind: Function,
739 lookup: "foo",
740 detail: "fn foo()",
741 },
742 ]
743 "###
744 );
745 }
746
747 #[test]
748 fn completes_qualified_macros() {
749 assert_debug_snapshot!(
750 do_reference_completion(
751 "
752 #[macro_export]
753 macro_rules! foo {
754 () => {}
755 }
756
757 fn main() {
758 let _ = crate::<|>
759 }
760 "
761 ),
762 @r###"
763 [
764 CompletionItem {
765 label: "foo!",
766 source_range: [179; 179),
767 delete: [179; 179),
768 insert: "foo!($0)",
769 kind: Macro,
770 detail: "#[macro_export]\nmacro_rules! foo",
771 },
772 CompletionItem {
773 label: "main()",
774 source_range: [179; 179),
775 delete: [179; 179),
776 insert: "main()$0",
777 kind: Function,
778 lookup: "main",
779 detail: "fn main()",
780 },
781 ]
782 "###
783 );
784 }
785}