diff options
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 151 |
1 files changed, 133 insertions, 18 deletions
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 8d8fe4645..903f11e4f 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -4,8 +4,8 @@ use crate::{ | |||
4 | }; | 4 | }; |
5 | use hir::{ | 5 | use hir::{ |
6 | db::{DefDatabase, HirDatabase}, | 6 | db::{DefDatabase, HirDatabase}, |
7 | AsAssocItem, AssocItem, AssocItemContainer, Crate, Function, ModPath, Module, ModuleDef, | 7 | AsAssocItem, AssocItem, AssocItemContainer, Crate, ModPath, Module, ModuleDef, PathResolution, |
8 | PathResolution, SourceAnalyzer, Trait, Type, | 8 | SourceAnalyzer, Trait, Type, |
9 | }; | 9 | }; |
10 | use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; | 10 | use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; |
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
@@ -115,7 +115,7 @@ impl AutoImportAssets { | |||
115 | match &self.import_candidate { | 115 | match &self.import_candidate { |
116 | ImportCandidate::UnqualifiedName(name) => name, | 116 | ImportCandidate::UnqualifiedName(name) => name, |
117 | ImportCandidate::QualifierStart(qualifier_start) => qualifier_start, | 117 | ImportCandidate::QualifierStart(qualifier_start) => qualifier_start, |
118 | ImportCandidate::TraitAssocItem(_, trait_function_name) => trait_function_name, | 118 | ImportCandidate::TraitAssocItem(_, trait_assoc_item_name) => trait_assoc_item_name, |
119 | ImportCandidate::TraitMethod(_, trait_method_name) => trait_method_name, | 119 | ImportCandidate::TraitMethod(_, trait_method_name) => trait_method_name, |
120 | } | 120 | } |
121 | } | 121 | } |
@@ -126,8 +126,8 @@ impl AutoImportAssets { | |||
126 | ImportCandidate::QualifierStart(qualifier_start) => { | 126 | ImportCandidate::QualifierStart(qualifier_start) => { |
127 | format!("Import {}", qualifier_start) | 127 | format!("Import {}", qualifier_start) |
128 | } | 128 | } |
129 | ImportCandidate::TraitAssocItem(_, trait_function_name) => { | 129 | ImportCandidate::TraitAssocItem(_, trait_assoc_item_name) => { |
130 | format!("Import a trait for item {}", trait_function_name) | 130 | format!("Import a trait for item {}", trait_assoc_item_name) |
131 | } | 131 | } |
132 | ImportCandidate::TraitMethod(_, trait_method_name) => { | 132 | ImportCandidate::TraitMethod(_, trait_method_name) => { |
133 | format!("Import a trait for method {}", trait_method_name) | 133 | format!("Import a trait for method {}", trait_method_name) |
@@ -142,16 +142,24 @@ impl AutoImportAssets { | |||
142 | .find_imports(&self.get_search_query()) | 142 | .find_imports(&self.get_search_query()) |
143 | .into_iter() | 143 | .into_iter() |
144 | .map(|module_def| match &self.import_candidate { | 144 | .map(|module_def| match &self.import_candidate { |
145 | ImportCandidate::TraitAssocItem(function_callee, _) => { | 145 | ImportCandidate::TraitAssocItem(assoc_item_type, _) => { |
146 | let located_assoc_item = match module_def { | ||
147 | ModuleDef::Function(located_function) => { | ||
148 | Some(AssocItem::Function(located_function)) | ||
149 | } | ||
150 | ModuleDef::Const(located_const) => Some(AssocItem::Const(located_const)), | ||
151 | _ => None, | ||
152 | }; | ||
153 | |||
146 | let mut applicable_traits = Vec::new(); | 154 | let mut applicable_traits = Vec::new(); |
147 | if let ModuleDef::Function(located_function) = module_def { | 155 | if let Some(located_assoc_item) = located_assoc_item { |
148 | let trait_candidates: FxHashSet<_> = | 156 | let trait_candidates: FxHashSet<_> = |
149 | Self::get_trait_candidates(db, located_function, current_crate) | 157 | Self::get_trait_candidates(db, located_assoc_item, current_crate) |
150 | .into_iter() | 158 | .into_iter() |
151 | .map(|trait_candidate| trait_candidate.into()) | 159 | .map(|trait_candidate| trait_candidate.into()) |
152 | .collect(); | 160 | .collect(); |
153 | if !trait_candidates.is_empty() { | 161 | if !trait_candidates.is_empty() { |
154 | function_callee.iterate_path_candidates( | 162 | assoc_item_type.iterate_path_candidates( |
155 | db, | 163 | db, |
156 | current_crate, | 164 | current_crate, |
157 | &trait_candidates, | 165 | &trait_candidates, |
@@ -175,11 +183,14 @@ impl AutoImportAssets { | |||
175 | ImportCandidate::TraitMethod(function_callee, _) => { | 183 | ImportCandidate::TraitMethod(function_callee, _) => { |
176 | let mut applicable_traits = Vec::new(); | 184 | let mut applicable_traits = Vec::new(); |
177 | if let ModuleDef::Function(located_function) = module_def { | 185 | if let ModuleDef::Function(located_function) = module_def { |
178 | let trait_candidates: FxHashSet<_> = | 186 | let trait_candidates: FxHashSet<_> = Self::get_trait_candidates( |
179 | Self::get_trait_candidates(db, located_function, current_crate) | 187 | db, |
180 | .into_iter() | 188 | AssocItem::Function(located_function), |
181 | .map(|trait_candidate| trait_candidate.into()) | 189 | current_crate, |
182 | .collect(); | 190 | ) |
191 | .into_iter() | ||
192 | .map(|trait_candidate| trait_candidate.into()) | ||
193 | .collect(); | ||
183 | if !trait_candidates.is_empty() { | 194 | if !trait_candidates.is_empty() { |
184 | function_callee.iterate_method_candidates( | 195 | function_callee.iterate_method_candidates( |
185 | db, | 196 | db, |
@@ -215,7 +226,7 @@ impl AutoImportAssets { | |||
215 | 226 | ||
216 | fn get_trait_candidates( | 227 | fn get_trait_candidates( |
217 | db: &RootDatabase, | 228 | db: &RootDatabase, |
218 | called_function: Function, | 229 | called_assoc_item: AssocItem, |
219 | root_crate: Crate, | 230 | root_crate: Crate, |
220 | ) -> FxHashSet<Trait> { | 231 | ) -> FxHashSet<Trait> { |
221 | let _p = profile("auto_import::get_trait_candidates"); | 232 | let _p = profile("auto_import::get_trait_candidates"); |
@@ -235,7 +246,7 @@ impl AutoImportAssets { | |||
235 | if trait_candidate | 246 | if trait_candidate |
236 | .items(db) | 247 | .items(db) |
237 | .into_iter() | 248 | .into_iter() |
238 | .any(|item| item == AssocItem::Function(called_function)) => | 249 | .any(|item| item == called_assoc_item) => |
239 | { | 250 | { |
240 | Some(trait_candidate) | 251 | Some(trait_candidate) |
241 | } | 252 | } |
@@ -302,9 +313,9 @@ impl ImportCandidate { | |||
302 | } else { | 313 | } else { |
303 | source_analyzer.resolve_path(db, &qualifier)? | 314 | source_analyzer.resolve_path(db, &qualifier)? |
304 | }; | 315 | }; |
305 | if let PathResolution::Def(ModuleDef::Adt(function_callee)) = qualifier_resolution { | 316 | if let PathResolution::Def(ModuleDef::Adt(assoc_item_path)) = qualifier_resolution { |
306 | Some(ImportCandidate::TraitAssocItem( | 317 | Some(ImportCandidate::TraitAssocItem( |
307 | function_callee.ty(db), | 318 | assoc_item_path.ty(db), |
308 | segment.syntax().to_string(), | 319 | segment.syntax().to_string(), |
309 | )) | 320 | )) |
310 | } else { | 321 | } else { |
@@ -581,6 +592,39 @@ mod tests { | |||
581 | } | 592 | } |
582 | 593 | ||
583 | #[test] | 594 | #[test] |
595 | fn associated_struct_const() { | ||
596 | check_assist( | ||
597 | auto_import, | ||
598 | r" | ||
599 | mod test_mod { | ||
600 | pub struct TestStruct {} | ||
601 | impl TestStruct { | ||
602 | const TEST_CONST: u8 = 42; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | fn main() { | ||
607 | TestStruct::TEST_CONST<|> | ||
608 | } | ||
609 | ", | ||
610 | r" | ||
611 | use test_mod::TestStruct; | ||
612 | |||
613 | mod test_mod { | ||
614 | pub struct TestStruct {} | ||
615 | impl TestStruct { | ||
616 | const TEST_CONST: u8 = 42; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | fn main() { | ||
621 | TestStruct::TEST_CONST<|> | ||
622 | } | ||
623 | ", | ||
624 | ); | ||
625 | } | ||
626 | |||
627 | #[test] | ||
584 | fn associated_trait_function() { | 628 | fn associated_trait_function() { |
585 | check_assist( | 629 | check_assist( |
586 | auto_import, | 630 | auto_import, |
@@ -652,6 +696,77 @@ mod tests { | |||
652 | } | 696 | } |
653 | 697 | ||
654 | #[test] | 698 | #[test] |
699 | fn associated_trait_const() { | ||
700 | check_assist( | ||
701 | auto_import, | ||
702 | r" | ||
703 | mod test_mod { | ||
704 | pub trait TestTrait { | ||
705 | const TEST_CONST: u8; | ||
706 | } | ||
707 | pub struct TestStruct {} | ||
708 | impl TestTrait for TestStruct { | ||
709 | const TEST_CONST: u8 = 42; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | fn main() { | ||
714 | test_mod::TestStruct::TEST_CONST<|> | ||
715 | } | ||
716 | ", | ||
717 | r" | ||
718 | use test_mod::TestTrait; | ||
719 | |||
720 | mod test_mod { | ||
721 | pub trait TestTrait { | ||
722 | const TEST_CONST: u8; | ||
723 | } | ||
724 | pub struct TestStruct {} | ||
725 | impl TestTrait for TestStruct { | ||
726 | const TEST_CONST: u8 = 42; | ||
727 | } | ||
728 | } | ||
729 | |||
730 | fn main() { | ||
731 | test_mod::TestStruct::TEST_CONST<|> | ||
732 | } | ||
733 | ", | ||
734 | ); | ||
735 | } | ||
736 | |||
737 | #[test] | ||
738 | fn not_applicable_for_imported_trait_for_const() { | ||
739 | check_assist_not_applicable( | ||
740 | auto_import, | ||
741 | r" | ||
742 | mod test_mod { | ||
743 | pub trait TestTrait { | ||
744 | const TEST_CONST: u8; | ||
745 | } | ||
746 | pub trait TestTrait2 { | ||
747 | const TEST_CONST: f64; | ||
748 | } | ||
749 | pub enum TestEnum { | ||
750 | One, | ||
751 | Two, | ||
752 | } | ||
753 | impl TestTrait2 for TestEnum { | ||
754 | const TEST_CONST: f64 = 42.0; | ||
755 | } | ||
756 | impl TestTrait for TestEnum { | ||
757 | const TEST_CONST: u8 = 42; | ||
758 | } | ||
759 | } | ||
760 | |||
761 | use test_mod::TestTrait2; | ||
762 | fn main() { | ||
763 | test_mod::TestEnum::TEST_CONST<|>; | ||
764 | } | ||
765 | ", | ||
766 | ) | ||
767 | } | ||
768 | |||
769 | #[test] | ||
655 | fn trait_method() { | 770 | fn trait_method() { |
656 | check_assist( | 771 | check_assist( |
657 | auto_import, | 772 | auto_import, |