diff options
author | Kirill Bulatov <[email protected]> | 2021-02-28 08:32:15 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2021-03-08 21:59:20 +0000 |
commit | 89d410cef571f5fa7631b17e2fbe52a8f8f03990 (patch) | |
tree | 6c40354741dda2072ef08f1bab9920547277bdd0 /crates/ide_db | |
parent | 9482353fa8e1e88cb720a029b9bb6304819c7399 (diff) |
Do not propose already imported imports
Diffstat (limited to 'crates/ide_db')
-rw-r--r-- | crates/ide_db/src/helpers/import_assets.rs | 43 |
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 @@ | |||
2 | use either::Either; | 2 | use either::Either; |
3 | use hir::{ | 3 | use 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 | }; |
7 | use rustc_hash::FxHashSet; | 7 | use rustc_hash::FxHashSet; |
8 | use syntax::{ast, AstNode}; | 8 | use syntax::{ast, AstNode}; |
@@ -62,33 +62,38 @@ impl NameToImport { | |||
62 | } | 62 | } |
63 | 63 | ||
64 | #[derive(Debug)] | 64 | #[derive(Debug)] |
65 | pub struct ImportAssets { | 65 | pub 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 | ||
70 | impl ImportAssets { | 71 | impl<'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 | ||
158 | impl ImportAssets { | 167 | impl<'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 | ||