diff options
Diffstat (limited to 'crates/ra_assists/src/handlers/auto_import.rs')
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 279 |
1 files changed, 262 insertions, 17 deletions
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index edf96d50e..947be3b9b 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -5,7 +5,7 @@ use hir::{ | |||
5 | AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, | 5 | AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, |
6 | Type, | 6 | Type, |
7 | }; | 7 | }; |
8 | use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; | 8 | use ra_ide_db::{imports_locator, RootDatabase}; |
9 | use ra_prof::profile; | 9 | use ra_prof::profile; |
10 | use ra_syntax::{ | 10 | use ra_syntax::{ |
11 | ast::{self, AstNode}, | 11 | ast::{self, AstNode}, |
@@ -13,7 +13,9 @@ use ra_syntax::{ | |||
13 | }; | 13 | }; |
14 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
15 | 15 | ||
16 | use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, GroupLabel}; | 16 | use crate::{ |
17 | utils::insert_use_statement, AssistContext, AssistId, AssistKind, Assists, GroupLabel, | ||
18 | }; | ||
17 | 19 | ||
18 | // Assist: auto_import | 20 | // Assist: auto_import |
19 | // | 21 | // |
@@ -35,8 +37,8 @@ use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, Group | |||
35 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | 37 | // # pub mod std { pub mod collections { pub struct HashMap { } } } |
36 | // ``` | 38 | // ``` |
37 | pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 39 | pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
38 | let auto_import_assets = AutoImportAssets::new(&ctx)?; | 40 | let auto_import_assets = AutoImportAssets::new(ctx)?; |
39 | let proposed_imports = auto_import_assets.search_for_imports(ctx.db); | 41 | let proposed_imports = auto_import_assets.search_for_imports(ctx); |
40 | if proposed_imports.is_empty() { | 42 | if proposed_imports.is_empty() { |
41 | return None; | 43 | return None; |
42 | } | 44 | } |
@@ -46,7 +48,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
46 | for import in proposed_imports { | 48 | for import in proposed_imports { |
47 | acc.add_group( | 49 | acc.add_group( |
48 | &group, | 50 | &group, |
49 | AssistId("auto_import"), | 51 | AssistId("auto_import", AssistKind::QuickFix), |
50 | format!("Import `{}`", &import), | 52 | format!("Import `{}`", &import), |
51 | range, | 53 | range, |
52 | |builder| { | 54 | |builder| { |
@@ -127,11 +129,11 @@ impl AutoImportAssets { | |||
127 | GroupLabel(name) | 129 | GroupLabel(name) |
128 | } | 130 | } |
129 | 131 | ||
130 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { | 132 | fn search_for_imports(&self, ctx: &AssistContext) -> BTreeSet<ModPath> { |
131 | let _p = profile("auto_import::search_for_imports"); | 133 | let _p = profile("auto_import::search_for_imports"); |
134 | let db = ctx.db(); | ||
132 | let current_crate = self.module_with_name_to_import.krate(); | 135 | let current_crate = self.module_with_name_to_import.krate(); |
133 | ImportsLocator::new(db) | 136 | imports_locator::find_imports(&ctx.sema, current_crate, &self.get_search_query()) |
134 | .find_imports(&self.get_search_query()) | ||
135 | .into_iter() | 137 | .into_iter() |
136 | .filter_map(|candidate| match &self.import_candidate { | 138 | .filter_map(|candidate| match &self.import_candidate { |
137 | ImportCandidate::TraitAssocItem(assoc_item_type, _) => { | 139 | ImportCandidate::TraitAssocItem(assoc_item_type, _) => { |
@@ -488,16 +490,17 @@ mod tests { | |||
488 | check_assist( | 490 | check_assist( |
489 | auto_import, | 491 | auto_import, |
490 | r" | 492 | r" |
491 | //- /lib.rs crate:crate_with_macro | 493 | //- /lib.rs crate:crate_with_macro |
492 | #[macro_export] | 494 | #[macro_export] |
493 | macro_rules! foo { | 495 | macro_rules! foo { |
494 | () => () | 496 | () => () |
495 | } | 497 | } |
496 | 498 | ||
497 | //- /main.rs crate:main deps:crate_with_macro | 499 | //- /main.rs crate:main deps:crate_with_macro |
498 | fn main() { | 500 | fn main() { |
499 | foo<|> | 501 | foo<|> |
500 | }", | 502 | } |
503 | ", | ||
501 | r"use crate_with_macro::foo; | 504 | r"use crate_with_macro::foo; |
502 | 505 | ||
503 | fn main() { | 506 | fn main() { |
@@ -810,6 +813,146 @@ fn main() { | |||
810 | } | 813 | } |
811 | 814 | ||
812 | #[test] | 815 | #[test] |
816 | fn trait_method_cross_crate() { | ||
817 | check_assist( | ||
818 | auto_import, | ||
819 | r" | ||
820 | //- /main.rs crate:main deps:dep | ||
821 | fn main() { | ||
822 | let test_struct = dep::test_mod::TestStruct {}; | ||
823 | test_struct.test_meth<|>od() | ||
824 | } | ||
825 | //- /dep.rs crate:dep | ||
826 | pub mod test_mod { | ||
827 | pub trait TestTrait { | ||
828 | fn test_method(&self); | ||
829 | } | ||
830 | pub struct TestStruct {} | ||
831 | impl TestTrait for TestStruct { | ||
832 | fn test_method(&self) {} | ||
833 | } | ||
834 | } | ||
835 | ", | ||
836 | r" | ||
837 | use dep::test_mod::TestTrait; | ||
838 | |||
839 | fn main() { | ||
840 | let test_struct = dep::test_mod::TestStruct {}; | ||
841 | test_struct.test_method() | ||
842 | } | ||
843 | ", | ||
844 | ); | ||
845 | } | ||
846 | |||
847 | #[test] | ||
848 | fn assoc_fn_cross_crate() { | ||
849 | check_assist( | ||
850 | auto_import, | ||
851 | r" | ||
852 | //- /main.rs crate:main deps:dep | ||
853 | fn main() { | ||
854 | dep::test_mod::TestStruct::test_func<|>tion | ||
855 | } | ||
856 | //- /dep.rs crate:dep | ||
857 | pub mod test_mod { | ||
858 | pub trait TestTrait { | ||
859 | fn test_function(); | ||
860 | } | ||
861 | pub struct TestStruct {} | ||
862 | impl TestTrait for TestStruct { | ||
863 | fn test_function() {} | ||
864 | } | ||
865 | } | ||
866 | ", | ||
867 | r" | ||
868 | use dep::test_mod::TestTrait; | ||
869 | |||
870 | fn main() { | ||
871 | dep::test_mod::TestStruct::test_function | ||
872 | } | ||
873 | ", | ||
874 | ); | ||
875 | } | ||
876 | |||
877 | #[test] | ||
878 | fn assoc_const_cross_crate() { | ||
879 | check_assist( | ||
880 | auto_import, | ||
881 | r" | ||
882 | //- /main.rs crate:main deps:dep | ||
883 | fn main() { | ||
884 | dep::test_mod::TestStruct::CONST<|> | ||
885 | } | ||
886 | //- /dep.rs crate:dep | ||
887 | pub mod test_mod { | ||
888 | pub trait TestTrait { | ||
889 | const CONST: bool; | ||
890 | } | ||
891 | pub struct TestStruct {} | ||
892 | impl TestTrait for TestStruct { | ||
893 | const CONST: bool = true; | ||
894 | } | ||
895 | } | ||
896 | ", | ||
897 | r" | ||
898 | use dep::test_mod::TestTrait; | ||
899 | |||
900 | fn main() { | ||
901 | dep::test_mod::TestStruct::CONST | ||
902 | } | ||
903 | ", | ||
904 | ); | ||
905 | } | ||
906 | |||
907 | #[test] | ||
908 | fn assoc_fn_as_method_cross_crate() { | ||
909 | check_assist_not_applicable( | ||
910 | auto_import, | ||
911 | r" | ||
912 | //- /main.rs crate:main deps:dep | ||
913 | fn main() { | ||
914 | let test_struct = dep::test_mod::TestStruct {}; | ||
915 | test_struct.test_func<|>tion() | ||
916 | } | ||
917 | //- /dep.rs crate:dep | ||
918 | pub mod test_mod { | ||
919 | pub trait TestTrait { | ||
920 | fn test_function(); | ||
921 | } | ||
922 | pub struct TestStruct {} | ||
923 | impl TestTrait for TestStruct { | ||
924 | fn test_function() {} | ||
925 | } | ||
926 | } | ||
927 | ", | ||
928 | ); | ||
929 | } | ||
930 | |||
931 | #[test] | ||
932 | fn private_trait_cross_crate() { | ||
933 | check_assist_not_applicable( | ||
934 | auto_import, | ||
935 | r" | ||
936 | //- /main.rs crate:main deps:dep | ||
937 | fn main() { | ||
938 | let test_struct = dep::test_mod::TestStruct {}; | ||
939 | test_struct.test_meth<|>od() | ||
940 | } | ||
941 | //- /dep.rs crate:dep | ||
942 | pub mod test_mod { | ||
943 | trait TestTrait { | ||
944 | fn test_method(&self); | ||
945 | } | ||
946 | pub struct TestStruct {} | ||
947 | impl TestTrait for TestStruct { | ||
948 | fn test_method(&self) {} | ||
949 | } | ||
950 | } | ||
951 | ", | ||
952 | ); | ||
953 | } | ||
954 | |||
955 | #[test] | ||
813 | fn not_applicable_for_imported_trait_for_method() { | 956 | fn not_applicable_for_imported_trait_for_method() { |
814 | check_assist_not_applicable( | 957 | check_assist_not_applicable( |
815 | auto_import, | 958 | auto_import, |
@@ -841,4 +984,106 @@ fn main() { | |||
841 | ", | 984 | ", |
842 | ) | 985 | ) |
843 | } | 986 | } |
987 | |||
988 | #[test] | ||
989 | fn dep_import() { | ||
990 | check_assist( | ||
991 | auto_import, | ||
992 | r" | ||
993 | //- /lib.rs crate:dep | ||
994 | pub struct Struct; | ||
995 | |||
996 | //- /main.rs crate:main deps:dep | ||
997 | fn main() { | ||
998 | Struct<|> | ||
999 | } | ||
1000 | ", | ||
1001 | r"use dep::Struct; | ||
1002 | |||
1003 | fn main() { | ||
1004 | Struct | ||
1005 | } | ||
1006 | ", | ||
1007 | ); | ||
1008 | } | ||
1009 | |||
1010 | #[test] | ||
1011 | fn whole_segment() { | ||
1012 | // Tests that only imports whose last segment matches the identifier get suggested. | ||
1013 | check_assist( | ||
1014 | auto_import, | ||
1015 | r" | ||
1016 | //- /lib.rs crate:dep | ||
1017 | pub mod fmt { | ||
1018 | pub trait Display {} | ||
1019 | } | ||
1020 | |||
1021 | pub fn panic_fmt() {} | ||
1022 | |||
1023 | //- /main.rs crate:main deps:dep | ||
1024 | struct S; | ||
1025 | |||
1026 | impl f<|>mt::Display for S {} | ||
1027 | ", | ||
1028 | r"use dep::fmt; | ||
1029 | |||
1030 | struct S; | ||
1031 | |||
1032 | impl fmt::Display for S {} | ||
1033 | ", | ||
1034 | ); | ||
1035 | } | ||
1036 | |||
1037 | #[test] | ||
1038 | fn macro_generated() { | ||
1039 | // Tests that macro-generated items are suggested from external crates. | ||
1040 | check_assist( | ||
1041 | auto_import, | ||
1042 | r" | ||
1043 | //- /lib.rs crate:dep | ||
1044 | macro_rules! mac { | ||
1045 | () => { | ||
1046 | pub struct Cheese; | ||
1047 | }; | ||
1048 | } | ||
1049 | |||
1050 | mac!(); | ||
1051 | |||
1052 | //- /main.rs crate:main deps:dep | ||
1053 | fn main() { | ||
1054 | Cheese<|>; | ||
1055 | } | ||
1056 | ", | ||
1057 | r"use dep::Cheese; | ||
1058 | |||
1059 | fn main() { | ||
1060 | Cheese; | ||
1061 | } | ||
1062 | ", | ||
1063 | ); | ||
1064 | } | ||
1065 | |||
1066 | #[test] | ||
1067 | fn casing() { | ||
1068 | // Tests that differently cased names don't interfere and we only suggest the matching one. | ||
1069 | check_assist( | ||
1070 | auto_import, | ||
1071 | r" | ||
1072 | //- /lib.rs crate:dep | ||
1073 | pub struct FMT; | ||
1074 | pub struct fmt; | ||
1075 | |||
1076 | //- /main.rs crate:main deps:dep | ||
1077 | fn main() { | ||
1078 | FMT<|>; | ||
1079 | } | ||
1080 | ", | ||
1081 | r"use dep::FMT; | ||
1082 | |||
1083 | fn main() { | ||
1084 | FMT; | ||
1085 | } | ||
1086 | ", | ||
1087 | ); | ||
1088 | } | ||
844 | } | 1089 | } |