aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/auto_import.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-08-13 16:33:38 +0100
committerAleksey Kladov <[email protected]>2020-08-13 16:33:38 +0100
commitfc34403018079ea053f26d0a31b7517053c7dd8c (patch)
tree500d7c2ec2179309be12a063634cb6a77c9af845 /crates/assists/src/handlers/auto_import.rs
parentae3abd6e575940eb1221acf26c09e96352f052fa (diff)
Rename ra_assists -> assists
Diffstat (limited to 'crates/assists/src/handlers/auto_import.rs')
-rw-r--r--crates/assists/src/handlers/auto_import.rs1088
1 files changed, 1088 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs
new file mode 100644
index 000000000..cce789972
--- /dev/null
+++ b/crates/assists/src/handlers/auto_import.rs
@@ -0,0 +1,1088 @@
1use std::collections::BTreeSet;
2
3use either::Either;
4use hir::{
5 AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait,
6 Type,
7};
8use ide_db::{imports_locator, RootDatabase};
9use rustc_hash::FxHashSet;
10use syntax::{
11 ast::{self, AstNode},
12 SyntaxNode,
13};
14
15use crate::{
16 utils::insert_use_statement, AssistContext, AssistId, AssistKind, Assists, GroupLabel,
17};
18
19// Assist: auto_import
20//
21// If the name is unresolved, provides all possible imports for it.
22//
23// ```
24// fn main() {
25// let map = HashMap<|>::new();
26// }
27// # pub mod std { pub mod collections { pub struct HashMap { } } }
28// ```
29// ->
30// ```
31// use std::collections::HashMap;
32//
33// fn main() {
34// let map = HashMap::new();
35// }
36// # pub mod std { pub mod collections { pub struct HashMap { } } }
37// ```
38pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
39 let auto_import_assets = AutoImportAssets::new(ctx)?;
40 let proposed_imports = auto_import_assets.search_for_imports(ctx);
41 if proposed_imports.is_empty() {
42 return None;
43 }
44
45 let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range;
46 let group = auto_import_assets.get_import_group_message();
47 for import in proposed_imports {
48 acc.add_group(
49 &group,
50 AssistId("auto_import", AssistKind::QuickFix),
51 format!("Import `{}`", &import),
52 range,
53 |builder| {
54 insert_use_statement(
55 &auto_import_assets.syntax_under_caret,
56 &import,
57 ctx,
58 builder.text_edit_builder(),
59 );
60 },
61 );
62 }
63 Some(())
64}
65
66#[derive(Debug)]
67struct AutoImportAssets {
68 import_candidate: ImportCandidate,
69 module_with_name_to_import: Module,
70 syntax_under_caret: SyntaxNode,
71}
72
73impl AutoImportAssets {
74 fn new(ctx: &AssistContext) -> Option<Self> {
75 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
76 Self::for_regular_path(path_under_caret, &ctx)
77 } else {
78 Self::for_method_call(ctx.find_node_at_offset_with_descend()?, &ctx)
79 }
80 }
81
82 fn for_method_call(method_call: ast::MethodCallExpr, ctx: &AssistContext) -> Option<Self> {
83 let syntax_under_caret = method_call.syntax().to_owned();
84 let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?;
85 Some(Self {
86 import_candidate: ImportCandidate::for_method_call(&ctx.sema, &method_call)?,
87 module_with_name_to_import,
88 syntax_under_caret,
89 })
90 }
91
92 fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistContext) -> Option<Self> {
93 let syntax_under_caret = path_under_caret.syntax().to_owned();
94 if syntax_under_caret.ancestors().find_map(ast::Use::cast).is_some() {
95 return None;
96 }
97
98 let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?;
99 Some(Self {
100 import_candidate: ImportCandidate::for_regular_path(&ctx.sema, &path_under_caret)?,
101 module_with_name_to_import,
102 syntax_under_caret,
103 })
104 }
105
106 fn get_search_query(&self) -> &str {
107 match &self.import_candidate {
108 ImportCandidate::UnqualifiedName(name) => name,
109 ImportCandidate::QualifierStart(qualifier_start) => qualifier_start,
110 ImportCandidate::TraitAssocItem(_, trait_assoc_item_name) => trait_assoc_item_name,
111 ImportCandidate::TraitMethod(_, trait_method_name) => trait_method_name,
112 }
113 }
114
115 fn get_import_group_message(&self) -> GroupLabel {
116 let name = match &self.import_candidate {
117 ImportCandidate::UnqualifiedName(name) => format!("Import {}", name),
118 ImportCandidate::QualifierStart(qualifier_start) => {
119 format!("Import {}", qualifier_start)
120 }
121 ImportCandidate::TraitAssocItem(_, trait_assoc_item_name) => {
122 format!("Import a trait for item {}", trait_assoc_item_name)
123 }
124 ImportCandidate::TraitMethod(_, trait_method_name) => {
125 format!("Import a trait for method {}", trait_method_name)
126 }
127 };
128 GroupLabel(name)
129 }
130
131 fn search_for_imports(&self, ctx: &AssistContext) -> BTreeSet<ModPath> {
132 let _p = profile::span("auto_import::search_for_imports");
133 let db = ctx.db();
134 let current_crate = self.module_with_name_to_import.krate();
135 imports_locator::find_imports(&ctx.sema, current_crate, &self.get_search_query())
136 .into_iter()
137 .filter_map(|candidate| match &self.import_candidate {
138 ImportCandidate::TraitAssocItem(assoc_item_type, _) => {
139 let located_assoc_item = match candidate {
140 Either::Left(ModuleDef::Function(located_function)) => located_function
141 .as_assoc_item(db)
142 .map(|assoc| assoc.container(db))
143 .and_then(Self::assoc_to_trait),
144 Either::Left(ModuleDef::Const(located_const)) => located_const
145 .as_assoc_item(db)
146 .map(|assoc| assoc.container(db))
147 .and_then(Self::assoc_to_trait),
148 _ => None,
149 }?;
150
151 let mut trait_candidates = FxHashSet::default();
152 trait_candidates.insert(located_assoc_item.into());
153
154 assoc_item_type
155 .iterate_path_candidates(
156 db,
157 current_crate,
158 &trait_candidates,
159 None,
160 |_, assoc| Self::assoc_to_trait(assoc.container(db)),
161 )
162 .map(ModuleDef::from)
163 .map(Either::Left)
164 }
165 ImportCandidate::TraitMethod(function_callee, _) => {
166 let located_assoc_item =
167 if let Either::Left(ModuleDef::Function(located_function)) = candidate {
168 located_function
169 .as_assoc_item(db)
170 .map(|assoc| assoc.container(db))
171 .and_then(Self::assoc_to_trait)
172 } else {
173 None
174 }?;
175
176 let mut trait_candidates = FxHashSet::default();
177 trait_candidates.insert(located_assoc_item.into());
178
179 function_callee
180 .iterate_method_candidates(
181 db,
182 current_crate,
183 &trait_candidates,
184 None,
185 |_, function| {
186 Self::assoc_to_trait(function.as_assoc_item(db)?.container(db))
187 },
188 )
189 .map(ModuleDef::from)
190 .map(Either::Left)
191 }
192 _ => Some(candidate),
193 })
194 .filter_map(|candidate| match candidate {
195 Either::Left(module_def) => {
196 self.module_with_name_to_import.find_use_path(db, module_def)
197 }
198 Either::Right(macro_def) => {
199 self.module_with_name_to_import.find_use_path(db, macro_def)
200 }
201 })
202 .filter(|use_path| !use_path.segments.is_empty())
203 .take(20)
204 .collect::<BTreeSet<_>>()
205 }
206
207 fn assoc_to_trait(assoc: AssocItemContainer) -> Option<Trait> {
208 if let AssocItemContainer::Trait(extracted_trait) = assoc {
209 Some(extracted_trait)
210 } else {
211 None
212 }
213 }
214}
215
216#[derive(Debug)]
217enum ImportCandidate {
218 /// Simple name like 'HashMap'
219 UnqualifiedName(String),
220 /// First part of the qualified name.
221 /// For 'std::collections::HashMap', that will be 'std'.
222 QualifierStart(String),
223 /// A trait associated function (with no self parameter) or associated constant.
224 /// For 'test_mod::TestEnum::test_function', `Type` is the `test_mod::TestEnum` expression type
225 /// and `String` is the `test_function`
226 TraitAssocItem(Type, String),
227 /// A trait method with self parameter.
228 /// For 'test_enum.test_method()', `Type` is the `test_enum` expression type
229 /// and `String` is the `test_method`
230 TraitMethod(Type, String),
231}
232
233impl ImportCandidate {
234 fn for_method_call(
235 sema: &Semantics<RootDatabase>,
236 method_call: &ast::MethodCallExpr,
237 ) -> Option<Self> {
238 if sema.resolve_method_call(method_call).is_some() {
239 return None;
240 }
241 Some(Self::TraitMethod(
242 sema.type_of_expr(&method_call.expr()?)?,
243 method_call.name_ref()?.syntax().to_string(),
244 ))
245 }
246
247 fn for_regular_path(
248 sema: &Semantics<RootDatabase>,
249 path_under_caret: &ast::Path,
250 ) -> Option<Self> {
251 if sema.resolve_path(path_under_caret).is_some() {
252 return None;
253 }
254
255 let segment = path_under_caret.segment()?;
256 if let Some(qualifier) = path_under_caret.qualifier() {
257 let qualifier_start = qualifier.syntax().descendants().find_map(ast::NameRef::cast)?;
258 let qualifier_start_path =
259 qualifier_start.syntax().ancestors().find_map(ast::Path::cast)?;
260 if let Some(qualifier_start_resolution) = sema.resolve_path(&qualifier_start_path) {
261 let qualifier_resolution = if qualifier_start_path == qualifier {
262 qualifier_start_resolution
263 } else {
264 sema.resolve_path(&qualifier)?
265 };
266 if let PathResolution::Def(ModuleDef::Adt(assoc_item_path)) = qualifier_resolution {
267 Some(ImportCandidate::TraitAssocItem(
268 assoc_item_path.ty(sema.db),
269 segment.syntax().to_string(),
270 ))
271 } else {
272 None
273 }
274 } else {
275 Some(ImportCandidate::QualifierStart(qualifier_start.syntax().to_string()))
276 }
277 } else {
278 Some(ImportCandidate::UnqualifiedName(
279 segment.syntax().descendants().find_map(ast::NameRef::cast)?.syntax().to_string(),
280 ))
281 }
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
289
290 #[test]
291 fn applicable_when_found_an_import() {
292 check_assist(
293 auto_import,
294 r"
295 <|>PubStruct
296
297 pub mod PubMod {
298 pub struct PubStruct;
299 }
300 ",
301 r"
302 use PubMod::PubStruct;
303
304 PubStruct
305
306 pub mod PubMod {
307 pub struct PubStruct;
308 }
309 ",
310 );
311 }
312
313 #[test]
314 fn applicable_when_found_an_import_in_macros() {
315 check_assist(
316 auto_import,
317 r"
318 macro_rules! foo {
319 ($i:ident) => { fn foo(a: $i) {} }
320 }
321 foo!(Pub<|>Struct);
322
323 pub mod PubMod {
324 pub struct PubStruct;
325 }
326 ",
327 r"
328 use PubMod::PubStruct;
329
330 macro_rules! foo {
331 ($i:ident) => { fn foo(a: $i) {} }
332 }
333 foo!(PubStruct);
334
335 pub mod PubMod {
336 pub struct PubStruct;
337 }
338 ",
339 );
340 }
341
342 #[test]
343 fn auto_imports_are_merged() {
344 check_assist(
345 auto_import,
346 r"
347 use PubMod::PubStruct1;
348
349 struct Test {
350 test: Pub<|>Struct2<u8>,
351 }
352
353 pub mod PubMod {
354 pub struct PubStruct1;
355 pub struct PubStruct2<T> {
356 _t: T,
357 }
358 }
359 ",
360 r"
361 use PubMod::{PubStruct2, PubStruct1};
362
363 struct Test {
364 test: PubStruct2<u8>,
365 }
366
367 pub mod PubMod {
368 pub struct PubStruct1;
369 pub struct PubStruct2<T> {
370 _t: T,
371 }
372 }
373 ",
374 );
375 }
376
377 #[test]
378 fn applicable_when_found_multiple_imports() {
379 check_assist(
380 auto_import,
381 r"
382 PubSt<|>ruct
383
384 pub mod PubMod1 {
385 pub struct PubStruct;
386 }
387 pub mod PubMod2 {
388 pub struct PubStruct;
389 }
390 pub mod PubMod3 {
391 pub struct PubStruct;
392 }
393 ",
394 r"
395 use PubMod3::PubStruct;
396
397 PubStruct
398
399 pub mod PubMod1 {
400 pub struct PubStruct;
401 }
402 pub mod PubMod2 {
403 pub struct PubStruct;
404 }
405 pub mod PubMod3 {
406 pub struct PubStruct;
407 }
408 ",
409 );
410 }
411
412 #[test]
413 fn not_applicable_for_already_imported_types() {
414 check_assist_not_applicable(
415 auto_import,
416 r"
417 use PubMod::PubStruct;
418
419 PubStruct<|>
420
421 pub mod PubMod {
422 pub struct PubStruct;
423 }
424 ",
425 );
426 }
427
428 #[test]
429 fn not_applicable_for_types_with_private_paths() {
430 check_assist_not_applicable(
431 auto_import,
432 r"
433 PrivateStruct<|>
434
435 pub mod PubMod {
436 struct PrivateStruct;
437 }
438 ",
439 );
440 }
441
442 #[test]
443 fn not_applicable_when_no_imports_found() {
444 check_assist_not_applicable(
445 auto_import,
446 "
447 PubStruct<|>",
448 );
449 }
450
451 #[test]
452 fn not_applicable_in_import_statements() {
453 check_assist_not_applicable(
454 auto_import,
455 r"
456 use PubStruct<|>;
457
458 pub mod PubMod {
459 pub struct PubStruct;
460 }",
461 );
462 }
463
464 #[test]
465 fn function_import() {
466 check_assist(
467 auto_import,
468 r"
469 test_function<|>
470
471 pub mod PubMod {
472 pub fn test_function() {};
473 }
474 ",
475 r"
476 use PubMod::test_function;
477
478 test_function
479
480 pub mod PubMod {
481 pub fn test_function() {};
482 }
483 ",
484 );
485 }
486
487 #[test]
488 fn macro_import() {
489 check_assist(
490 auto_import,
491 r"
492//- /lib.rs crate:crate_with_macro
493#[macro_export]
494macro_rules! foo {
495 () => ()
496}
497
498//- /main.rs crate:main deps:crate_with_macro
499fn main() {
500 foo<|>
501}
502",
503 r"use crate_with_macro::foo;
504
505fn main() {
506 foo
507}
508",
509 );
510 }
511
512 #[test]
513 fn auto_import_target() {
514 check_assist_target(
515 auto_import,
516 r"
517 struct AssistInfo {
518 group_label: Option<<|>GroupLabel>,
519 }
520
521 mod m { pub struct GroupLabel; }
522 ",
523 "GroupLabel",
524 )
525 }
526
527 #[test]
528 fn not_applicable_when_path_start_is_imported() {
529 check_assist_not_applicable(
530 auto_import,
531 r"
532 pub mod mod1 {
533 pub mod mod2 {
534 pub mod mod3 {
535 pub struct TestStruct;
536 }
537 }
538 }
539
540 use mod1::mod2;
541 fn main() {
542 mod2::mod3::TestStruct<|>
543 }
544 ",
545 );
546 }
547
548 #[test]
549 fn not_applicable_for_imported_function() {
550 check_assist_not_applicable(
551 auto_import,
552 r"
553 pub mod test_mod {
554 pub fn test_function() {}
555 }
556
557 use test_mod::test_function;
558 fn main() {
559 test_function<|>
560 }
561 ",
562 );
563 }
564
565 #[test]
566 fn associated_struct_function() {
567 check_assist(
568 auto_import,
569 r"
570 mod test_mod {
571 pub struct TestStruct {}
572 impl TestStruct {
573 pub fn test_function() {}
574 }
575 }
576
577 fn main() {
578 TestStruct::test_function<|>
579 }
580 ",
581 r"
582 use test_mod::TestStruct;
583
584 mod test_mod {
585 pub struct TestStruct {}
586 impl TestStruct {
587 pub fn test_function() {}
588 }
589 }
590
591 fn main() {
592 TestStruct::test_function
593 }
594 ",
595 );
596 }
597
598 #[test]
599 fn associated_struct_const() {
600 check_assist(
601 auto_import,
602 r"
603 mod test_mod {
604 pub struct TestStruct {}
605 impl TestStruct {
606 const TEST_CONST: u8 = 42;
607 }
608 }
609
610 fn main() {
611 TestStruct::TEST_CONST<|>
612 }
613 ",
614 r"
615 use test_mod::TestStruct;
616
617 mod test_mod {
618 pub struct TestStruct {}
619 impl TestStruct {
620 const TEST_CONST: u8 = 42;
621 }
622 }
623
624 fn main() {
625 TestStruct::TEST_CONST
626 }
627 ",
628 );
629 }
630
631 #[test]
632 fn associated_trait_function() {
633 check_assist(
634 auto_import,
635 r"
636 mod test_mod {
637 pub trait TestTrait {
638 fn test_function();
639 }
640 pub struct TestStruct {}
641 impl TestTrait for TestStruct {
642 fn test_function() {}
643 }
644 }
645
646 fn main() {
647 test_mod::TestStruct::test_function<|>
648 }
649 ",
650 r"
651 use test_mod::TestTrait;
652
653 mod test_mod {
654 pub trait TestTrait {
655 fn test_function();
656 }
657 pub struct TestStruct {}
658 impl TestTrait for TestStruct {
659 fn test_function() {}
660 }
661 }
662
663 fn main() {
664 test_mod::TestStruct::test_function
665 }
666 ",
667 );
668 }
669
670 #[test]
671 fn not_applicable_for_imported_trait_for_function() {
672 check_assist_not_applicable(
673 auto_import,
674 r"
675 mod test_mod {
676 pub trait TestTrait {
677 fn test_function();
678 }
679 pub trait TestTrait2 {
680 fn test_function();
681 }
682 pub enum TestEnum {
683 One,
684 Two,
685 }
686 impl TestTrait2 for TestEnum {
687 fn test_function() {}
688 }
689 impl TestTrait for TestEnum {
690 fn test_function() {}
691 }
692 }
693
694 use test_mod::TestTrait2;
695 fn main() {
696 test_mod::TestEnum::test_function<|>;
697 }
698 ",
699 )
700 }
701
702 #[test]
703 fn associated_trait_const() {
704 check_assist(
705 auto_import,
706 r"
707 mod test_mod {
708 pub trait TestTrait {
709 const TEST_CONST: u8;
710 }
711 pub struct TestStruct {}
712 impl TestTrait for TestStruct {
713 const TEST_CONST: u8 = 42;
714 }
715 }
716
717 fn main() {
718 test_mod::TestStruct::TEST_CONST<|>
719 }
720 ",
721 r"
722 use test_mod::TestTrait;
723
724 mod test_mod {
725 pub trait TestTrait {
726 const TEST_CONST: u8;
727 }
728 pub struct TestStruct {}
729 impl TestTrait for TestStruct {
730 const TEST_CONST: u8 = 42;
731 }
732 }
733
734 fn main() {
735 test_mod::TestStruct::TEST_CONST
736 }
737 ",
738 );
739 }
740
741 #[test]
742 fn not_applicable_for_imported_trait_for_const() {
743 check_assist_not_applicable(
744 auto_import,
745 r"
746 mod test_mod {
747 pub trait TestTrait {
748 const TEST_CONST: u8;
749 }
750 pub trait TestTrait2 {
751 const TEST_CONST: f64;
752 }
753 pub enum TestEnum {
754 One,
755 Two,
756 }
757 impl TestTrait2 for TestEnum {
758 const TEST_CONST: f64 = 42.0;
759 }
760 impl TestTrait for TestEnum {
761 const TEST_CONST: u8 = 42;
762 }
763 }
764
765 use test_mod::TestTrait2;
766 fn main() {
767 test_mod::TestEnum::TEST_CONST<|>;
768 }
769 ",
770 )
771 }
772
773 #[test]
774 fn trait_method() {
775 check_assist(
776 auto_import,
777 r"
778 mod test_mod {
779 pub trait TestTrait {
780 fn test_method(&self);
781 }
782 pub struct TestStruct {}
783 impl TestTrait for TestStruct {
784 fn test_method(&self) {}
785 }
786 }
787
788 fn main() {
789 let test_struct = test_mod::TestStruct {};
790 test_struct.test_meth<|>od()
791 }
792 ",
793 r"
794 use test_mod::TestTrait;
795
796 mod test_mod {
797 pub trait TestTrait {
798 fn test_method(&self);
799 }
800 pub struct TestStruct {}
801 impl TestTrait for TestStruct {
802 fn test_method(&self) {}
803 }
804 }
805
806 fn main() {
807 let test_struct = test_mod::TestStruct {};
808 test_struct.test_method()
809 }
810 ",
811 );
812 }
813
814 #[test]
815 fn trait_method_cross_crate() {
816 check_assist(
817 auto_import,
818 r"
819 //- /main.rs crate:main deps:dep
820 fn main() {
821 let test_struct = dep::test_mod::TestStruct {};
822 test_struct.test_meth<|>od()
823 }
824 //- /dep.rs crate:dep
825 pub mod test_mod {
826 pub trait TestTrait {
827 fn test_method(&self);
828 }
829 pub struct TestStruct {}
830 impl TestTrait for TestStruct {
831 fn test_method(&self) {}
832 }
833 }
834 ",
835 r"
836 use dep::test_mod::TestTrait;
837
838 fn main() {
839 let test_struct = dep::test_mod::TestStruct {};
840 test_struct.test_method()
841 }
842 ",
843 );
844 }
845
846 #[test]
847 fn assoc_fn_cross_crate() {
848 check_assist(
849 auto_import,
850 r"
851 //- /main.rs crate:main deps:dep
852 fn main() {
853 dep::test_mod::TestStruct::test_func<|>tion
854 }
855 //- /dep.rs crate:dep
856 pub mod test_mod {
857 pub trait TestTrait {
858 fn test_function();
859 }
860 pub struct TestStruct {}
861 impl TestTrait for TestStruct {
862 fn test_function() {}
863 }
864 }
865 ",
866 r"
867 use dep::test_mod::TestTrait;
868
869 fn main() {
870 dep::test_mod::TestStruct::test_function
871 }
872 ",
873 );
874 }
875
876 #[test]
877 fn assoc_const_cross_crate() {
878 check_assist(
879 auto_import,
880 r"
881 //- /main.rs crate:main deps:dep
882 fn main() {
883 dep::test_mod::TestStruct::CONST<|>
884 }
885 //- /dep.rs crate:dep
886 pub mod test_mod {
887 pub trait TestTrait {
888 const CONST: bool;
889 }
890 pub struct TestStruct {}
891 impl TestTrait for TestStruct {
892 const CONST: bool = true;
893 }
894 }
895 ",
896 r"
897 use dep::test_mod::TestTrait;
898
899 fn main() {
900 dep::test_mod::TestStruct::CONST
901 }
902 ",
903 );
904 }
905
906 #[test]
907 fn assoc_fn_as_method_cross_crate() {
908 check_assist_not_applicable(
909 auto_import,
910 r"
911 //- /main.rs crate:main deps:dep
912 fn main() {
913 let test_struct = dep::test_mod::TestStruct {};
914 test_struct.test_func<|>tion()
915 }
916 //- /dep.rs crate:dep
917 pub mod test_mod {
918 pub trait TestTrait {
919 fn test_function();
920 }
921 pub struct TestStruct {}
922 impl TestTrait for TestStruct {
923 fn test_function() {}
924 }
925 }
926 ",
927 );
928 }
929
930 #[test]
931 fn private_trait_cross_crate() {
932 check_assist_not_applicable(
933 auto_import,
934 r"
935 //- /main.rs crate:main deps:dep
936 fn main() {
937 let test_struct = dep::test_mod::TestStruct {};
938 test_struct.test_meth<|>od()
939 }
940 //- /dep.rs crate:dep
941 pub mod test_mod {
942 trait TestTrait {
943 fn test_method(&self);
944 }
945 pub struct TestStruct {}
946 impl TestTrait for TestStruct {
947 fn test_method(&self) {}
948 }
949 }
950 ",
951 );
952 }
953
954 #[test]
955 fn not_applicable_for_imported_trait_for_method() {
956 check_assist_not_applicable(
957 auto_import,
958 r"
959 mod test_mod {
960 pub trait TestTrait {
961 fn test_method(&self);
962 }
963 pub trait TestTrait2 {
964 fn test_method(&self);
965 }
966 pub enum TestEnum {
967 One,
968 Two,
969 }
970 impl TestTrait2 for TestEnum {
971 fn test_method(&self) {}
972 }
973 impl TestTrait for TestEnum {
974 fn test_method(&self) {}
975 }
976 }
977
978 use test_mod::TestTrait2;
979 fn main() {
980 let one = test_mod::TestEnum::One;
981 one.test<|>_method();
982 }
983 ",
984 )
985 }
986
987 #[test]
988 fn dep_import() {
989 check_assist(
990 auto_import,
991 r"
992//- /lib.rs crate:dep
993pub struct Struct;
994
995//- /main.rs crate:main deps:dep
996fn main() {
997 Struct<|>
998}
999",
1000 r"use dep::Struct;
1001
1002fn main() {
1003 Struct
1004}
1005",
1006 );
1007 }
1008
1009 #[test]
1010 fn whole_segment() {
1011 // Tests that only imports whose last segment matches the identifier get suggested.
1012 check_assist(
1013 auto_import,
1014 r"
1015//- /lib.rs crate:dep
1016pub mod fmt {
1017 pub trait Display {}
1018}
1019
1020pub fn panic_fmt() {}
1021
1022//- /main.rs crate:main deps:dep
1023struct S;
1024
1025impl f<|>mt::Display for S {}
1026",
1027 r"use dep::fmt;
1028
1029struct S;
1030
1031impl fmt::Display for S {}
1032",
1033 );
1034 }
1035
1036 #[test]
1037 fn macro_generated() {
1038 // Tests that macro-generated items are suggested from external crates.
1039 check_assist(
1040 auto_import,
1041 r"
1042//- /lib.rs crate:dep
1043macro_rules! mac {
1044 () => {
1045 pub struct Cheese;
1046 };
1047}
1048
1049mac!();
1050
1051//- /main.rs crate:main deps:dep
1052fn main() {
1053 Cheese<|>;
1054}
1055",
1056 r"use dep::Cheese;
1057
1058fn main() {
1059 Cheese;
1060}
1061",
1062 );
1063 }
1064
1065 #[test]
1066 fn casing() {
1067 // Tests that differently cased names don't interfere and we only suggest the matching one.
1068 check_assist(
1069 auto_import,
1070 r"
1071//- /lib.rs crate:dep
1072pub struct FMT;
1073pub struct fmt;
1074
1075//- /main.rs crate:main deps:dep
1076fn main() {
1077 FMT<|>;
1078}
1079",
1080 r"use dep::FMT;
1081
1082fn main() {
1083 FMT;
1084}
1085",
1086 );
1087 }
1088}