aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2021-02-28 08:32:15 +0000
committerKirill Bulatov <[email protected]>2021-03-08 21:59:20 +0000
commit89d410cef571f5fa7631b17e2fbe52a8f8f03990 (patch)
tree6c40354741dda2072ef08f1bab9920547277bdd0 /crates/ide_db
parent9482353fa8e1e88cb720a029b9bb6304819c7399 (diff)
Do not propose already imported imports
Diffstat (limited to 'crates/ide_db')
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs43
1 files changed, 34 insertions, 9 deletions
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 2e7a183d1..b25786928 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -2,7 +2,7 @@
2use either::Either; 2use either::Either;
3use hir::{ 3use hir::{
4 AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module, 4 AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module,
5 ModuleDef, PathResolution, PrefixKind, Semantics, Type, 5 ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type,
6}; 6};
7use rustc_hash::FxHashSet; 7use rustc_hash::FxHashSet;
8use syntax::{ast, AstNode}; 8use syntax::{ast, AstNode};
@@ -62,33 +62,38 @@ impl NameToImport {
62} 62}
63 63
64#[derive(Debug)] 64#[derive(Debug)]
65pub struct ImportAssets { 65pub struct ImportAssets<'a> {
66 import_candidate: ImportCandidate, 66 import_candidate: ImportCandidate,
67 module_with_candidate: Module, 67 module_with_candidate: Module,
68 scope: SemanticsScope<'a>,
68} 69}
69 70
70impl ImportAssets { 71impl<'a> ImportAssets<'a> {
71 pub fn for_method_call( 72 pub fn for_method_call(
72 method_call: &ast::MethodCallExpr, 73 method_call: &ast::MethodCallExpr,
73 sema: &Semantics<RootDatabase>, 74 sema: &'a Semantics<RootDatabase>,
74 ) -> Option<Self> { 75 ) -> Option<Self> {
76 let scope = sema.scope(method_call.syntax());
75 Some(Self { 77 Some(Self {
76 import_candidate: ImportCandidate::for_method_call(sema, method_call)?, 78 import_candidate: ImportCandidate::for_method_call(sema, method_call)?,
77 module_with_candidate: sema.scope(method_call.syntax()).module()?, 79 module_with_candidate: scope.module()?,
80 scope,
78 }) 81 })
79 } 82 }
80 83
81 pub fn for_exact_path( 84 pub fn for_exact_path(
82 fully_qualified_path: &ast::Path, 85 fully_qualified_path: &ast::Path,
83 sema: &Semantics<RootDatabase>, 86 sema: &'a Semantics<RootDatabase>,
84 ) -> Option<Self> { 87 ) -> Option<Self> {
85 let syntax_under_caret = fully_qualified_path.syntax(); 88 let syntax_under_caret = fully_qualified_path.syntax();
86 if syntax_under_caret.ancestors().find_map(ast::Use::cast).is_some() { 89 if syntax_under_caret.ancestors().find_map(ast::Use::cast).is_some() {
87 return None; 90 return None;
88 } 91 }
92 let scope = sema.scope(syntax_under_caret);
89 Some(Self { 93 Some(Self {
90 import_candidate: ImportCandidate::for_regular_path(sema, fully_qualified_path)?, 94 import_candidate: ImportCandidate::for_regular_path(sema, fully_qualified_path)?,
91 module_with_candidate: sema.scope(syntax_under_caret).module()?, 95 module_with_candidate: scope.module()?,
96 scope,
92 }) 97 })
93 } 98 }
94 99
@@ -97,10 +102,12 @@ impl ImportAssets {
97 qualifier: Option<ast::Path>, 102 qualifier: Option<ast::Path>,
98 fuzzy_name: String, 103 fuzzy_name: String,
99 sema: &Semantics<RootDatabase>, 104 sema: &Semantics<RootDatabase>,
105 scope: SemanticsScope<'a>,
100 ) -> Option<Self> { 106 ) -> Option<Self> {
101 Some(Self { 107 Some(Self {
102 import_candidate: ImportCandidate::for_fuzzy_path(qualifier, fuzzy_name, sema)?, 108 import_candidate: ImportCandidate::for_fuzzy_path(qualifier, fuzzy_name, sema)?,
103 module_with_candidate, 109 module_with_candidate,
110 scope,
104 }) 111 })
105 } 112 }
106 113
@@ -108,6 +115,7 @@ impl ImportAssets {
108 module_with_method_call: Module, 115 module_with_method_call: Module,
109 receiver_ty: Type, 116 receiver_ty: Type,
110 fuzzy_method_name: String, 117 fuzzy_method_name: String,
118 scope: SemanticsScope<'a>,
111 ) -> Option<Self> { 119 ) -> Option<Self> {
112 Some(Self { 120 Some(Self {
113 import_candidate: ImportCandidate::TraitMethod(TraitImportCandidate { 121 import_candidate: ImportCandidate::TraitMethod(TraitImportCandidate {
@@ -115,6 +123,7 @@ impl ImportAssets {
115 name: NameToImport::Fuzzy(fuzzy_method_name), 123 name: NameToImport::Fuzzy(fuzzy_method_name),
116 }), 124 }),
117 module_with_candidate: module_with_method_call, 125 module_with_candidate: module_with_method_call,
126 scope,
118 }) 127 })
119 } 128 }
120} 129}
@@ -155,7 +164,7 @@ impl LocatedImport {
155 } 164 }
156} 165}
157 166
158impl ImportAssets { 167impl<'a> ImportAssets<'a> {
159 pub fn import_candidate(&self) -> &ImportCandidate { 168 pub fn import_candidate(&self) -> &ImportCandidate {
160 &self.import_candidate 169 &self.import_candidate
161 } 170 }
@@ -189,6 +198,7 @@ impl ImportAssets {
189 prefixed: Option<PrefixKind>, 198 prefixed: Option<PrefixKind>,
190 ) -> Vec<LocatedImport> { 199 ) -> Vec<LocatedImport> {
191 let current_crate = self.module_with_candidate.krate(); 200 let current_crate = self.module_with_candidate.krate();
201 let scope_definitions = self.scope_definitions();
192 202
193 let imports_for_candidate_name = match self.name_to_import() { 203 let imports_for_candidate_name = match self.name_to_import() {
194 NameToImport::Exact(exact_name) => { 204 NameToImport::Exact(exact_name) => {
@@ -219,9 +229,25 @@ impl ImportAssets {
219 self.applicable_defs(sema.db, prefixed, imports_for_candidate_name) 229 self.applicable_defs(sema.db, prefixed, imports_for_candidate_name)
220 .into_iter() 230 .into_iter()
221 .filter(|import| import.import_path().len() > 1) 231 .filter(|import| import.import_path().len() > 1)
232 .filter(|import| {
233 let proposed_def = match import.item_to_import() {
234 ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()),
235 ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()),
236 ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()),
237 };
238 !scope_definitions.contains(&proposed_def)
239 })
222 .collect() 240 .collect()
223 } 241 }
224 242
243 fn scope_definitions(&self) -> FxHashSet<ScopeDef> {
244 let mut scope_definitions = FxHashSet::default();
245 self.scope.process_all_names(&mut |_, scope_def| {
246 scope_definitions.insert(scope_def);
247 });
248 scope_definitions
249 }
250
225 fn applicable_defs( 251 fn applicable_defs(
226 &self, 252 &self,
227 db: &RootDatabase, 253 db: &RootDatabase,
@@ -297,7 +323,6 @@ fn path_applicable_imports(
297 Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => (first_segment, qualifier), 323 Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => (first_segment, qualifier),
298 }; 324 };
299 325
300 // TODO kb zz.syntax().ast_node() <- two options are now proposed despite the trait being imported
301 let unresolved_qualifier_string = unresolved_qualifier.to_string(); 326 let unresolved_qualifier_string = unresolved_qualifier.to_string();
302 let unresolved_first_segment_string = unresolved_first_segment.to_string(); 327 let unresolved_first_segment_string = unresolved_first_segment.to_string();
303 328