aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs151
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};
5use hir::{ 5use 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};
10use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; 10use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase};
11use ra_prof::profile; 11use 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,