Skip to content

Commit 005bc49

Browse files
Test and initial refactoring
1 parent c484786 commit 005bc49

File tree

4 files changed

+101
-125
lines changed

4 files changed

+101
-125
lines changed

crates/ide_assists/src/handlers/auto_import.rs

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -220,41 +220,6 @@ mod tests {
220220
);
221221
}
222222

223-
#[test]
224-
fn auto_imports_are_merged() {
225-
check_assist(
226-
auto_import,
227-
r"
228-
use PubMod::PubStruct1;
229-
230-
struct Test {
231-
test: Pub$0Struct2<u8>,
232-
}
233-
234-
pub mod PubMod {
235-
pub struct PubStruct1;
236-
pub struct PubStruct2<T> {
237-
_t: T,
238-
}
239-
}
240-
",
241-
r"
242-
use PubMod::{PubStruct1, PubStruct2};
243-
244-
struct Test {
245-
test: PubStruct2<u8>,
246-
}
247-
248-
pub mod PubMod {
249-
pub struct PubStruct1;
250-
pub struct PubStruct2<T> {
251-
_t: T,
252-
}
253-
}
254-
",
255-
);
256-
}
257-
258223
#[test]
259224
fn applicable_when_found_multiple_imports() {
260225
check_assist(

crates/ide_assists/src/handlers/qualify_path.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
4545

4646
let qualify_candidate = match candidate {
4747
ImportCandidate::Path(candidate) => {
48-
if candidate.qualifier.is_some() {
48+
if candidate.unresolved_qualifier.is_some() {
4949
cov_mark::hit!(qualify_path_qualifier_start);
5050
let path = ast::Path::cast(syntax_under_caret)?;
5151
let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
@@ -192,7 +192,7 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel {
192192
fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String {
193193
match candidate {
194194
ImportCandidate::Path(candidate) => {
195-
if candidate.qualifier.is_some() {
195+
if candidate.unresolved_qualifier.is_some() {
196196
format!("Qualify with `{}`", &import)
197197
} else {
198198
format!("Qualify as `{}`", &import)

crates/ide_completion/src/completions/flyimport.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,15 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
168168
ctx.path_qual.clone(),
169169
fuzzy_name,
170170
&ctx.sema,
171-
);
171+
)?;
172172

173-
if matches!(assets_for_path.as_ref()?.import_candidate(), ImportCandidate::Path(_))
173+
if matches!(assets_for_path.import_candidate(), ImportCandidate::Path(_))
174174
&& fuzzy_name_length < 2
175175
{
176176
cov_mark::hit!(ignore_short_input_for_path);
177177
None
178178
} else {
179-
assets_for_path
179+
Some(assets_for_path)
180180
}
181181
}
182182
}
@@ -773,4 +773,35 @@ fn main() {
773773
}"#,
774774
);
775775
}
776+
777+
#[test]
778+
fn unresolved_qualifiers() {
779+
check_edit(
780+
"Item",
781+
r#"
782+
mod foo {
783+
pub mod bar {
784+
pub struct Item;
785+
}
786+
}
787+
788+
fn main() {
789+
bar::Ite$0
790+
}
791+
"#,
792+
r#"
793+
use foo::bar;
794+
795+
mod foo {
796+
pub mod bar {
797+
pub struct Item;
798+
}
799+
}
800+
801+
fn main() {
802+
bar::Item
803+
}
804+
"#,
805+
);
806+
}
776807
}

crates/ide_db/src/helpers/import_assets.rs

Lines changed: 65 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub struct TraitImportCandidate {
3131

3232
#[derive(Debug)]
3333
pub struct PathImportCandidate {
34-
pub qualifier: Option<ast::Path>,
34+
pub unresolved_qualifier: Option<ast::Path>,
3535
pub name: NameToImport,
3636
}
3737

@@ -82,38 +82,14 @@ impl ImportAssets {
8282
}
8383

8484
pub fn for_fuzzy_path(
85-
module_with_path: Module,
85+
module_with_candidate: Module,
8686
qualifier: Option<ast::Path>,
8787
fuzzy_name: String,
8888
sema: &Semantics<RootDatabase>,
8989
) -> Option<Self> {
90-
Some(match qualifier {
91-
Some(qualifier) => {
92-
let qualifier_resolution = sema.resolve_path(&qualifier)?;
93-
match qualifier_resolution {
94-
hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path)) => Self {
95-
import_candidate: ImportCandidate::TraitAssocItem(TraitImportCandidate {
96-
receiver_ty: assoc_item_path.ty(sema.db),
97-
name: NameToImport::Fuzzy(fuzzy_name),
98-
}),
99-
module_with_candidate: module_with_path,
100-
},
101-
_ => Self {
102-
import_candidate: ImportCandidate::Path(PathImportCandidate {
103-
qualifier: Some(qualifier),
104-
name: NameToImport::Fuzzy(fuzzy_name),
105-
}),
106-
module_with_candidate: module_with_path,
107-
},
108-
}
109-
}
110-
None => Self {
111-
import_candidate: ImportCandidate::Path(PathImportCandidate {
112-
qualifier: None,
113-
name: NameToImport::Fuzzy(fuzzy_name),
114-
}),
115-
module_with_candidate: module_with_path,
116-
},
90+
Some(Self {
91+
import_candidate: ImportCandidate::for_fuzzy_path(qualifier, fuzzy_name, sema)?,
92+
module_with_candidate,
11793
})
11894
}
11995

@@ -169,8 +145,9 @@ impl ImportAssets {
169145
prefixed: Option<hir::PrefixKind>,
170146
) -> Vec<(hir::ModPath, hir::ItemInNs)> {
171147
let current_crate = self.module_with_candidate.krate();
148+
let import_candidate = &self.import_candidate;
172149

173-
let unfiltered_imports = match self.name_to_import() {
150+
let imports_for_candidate_name = match self.name_to_import() {
174151
NameToImport::Exact(exact_name) => {
175152
imports_locator::find_exact_imports(sema, current_crate, exact_name.clone())
176153
}
@@ -180,11 +157,10 @@ impl ImportAssets {
180157
// and https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Blanket.20trait.20impls.20lookup
181158
// for the details
182159
NameToImport::Fuzzy(fuzzy_name) => {
183-
let (assoc_item_search, limit) = match self.import_candidate {
184-
ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_) => {
185-
(AssocItemSearch::AssocItemsOnly, None)
186-
}
187-
_ => (AssocItemSearch::Exclude, Some(DEFAULT_QUERY_SEARCH_LIMIT)),
160+
let (assoc_item_search, limit) = if import_candidate.is_trait_candidate() {
161+
(AssocItemSearch::AssocItemsOnly, None)
162+
} else {
163+
(AssocItemSearch::Exclude, Some(DEFAULT_QUERY_SEARCH_LIMIT))
188164
};
189165
imports_locator::find_similar_imports(
190166
sema,
@@ -198,33 +174,32 @@ impl ImportAssets {
198174

199175
let db = sema.db;
200176
let mut res =
201-
applicable_defs(self.import_candidate(), current_crate, db, unfiltered_imports)
177+
applicable_defs(import_candidate, current_crate, db, imports_for_candidate_name)
202178
.filter_map(|candidate| {
203179
let item: hir::ItemInNs = candidate.clone().either(Into::into, Into::into);
204180

205-
let item_to_search = match self.import_candidate {
206-
ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_) => {
207-
let canidate_trait = match candidate {
208-
Either::Left(module_def) => {
209-
module_def.as_assoc_item(db)?.containing_trait(db)
210-
}
211-
_ => None,
212-
}?;
213-
ModuleDef::from(canidate_trait).into()
214-
}
215-
_ => item,
181+
let item_to_search = if import_candidate.is_trait_candidate() {
182+
let canidate_trait = match candidate {
183+
Either::Left(module_def) => {
184+
module_def.as_assoc_item(db)?.containing_trait(db)
185+
}
186+
_ => None,
187+
}?;
188+
ModuleDef::from(canidate_trait).into()
189+
} else {
190+
item
216191
};
217-
218-
if let Some(prefix_kind) = prefixed {
192+
let mod_path = if let Some(prefix_kind) = prefixed {
219193
self.module_with_candidate.find_use_path_prefixed(
220194
db,
221195
item_to_search,
222196
prefix_kind,
223197
)
224198
} else {
225199
self.module_with_candidate.find_use_path(db, item_to_search)
226-
}
227-
.map(|path| (path, item))
200+
};
201+
202+
mod_path.zip(Some(item))
228203
})
229204
.filter(|(use_path, _)| use_path.len() > 1)
230205
.collect::<Vec<_>>();
@@ -239,6 +214,7 @@ fn applicable_defs<'a>(
239214
db: &RootDatabase,
240215
unfiltered_imports: Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a>,
241216
) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a> {
217+
// TODO kb this needs to consider various path prefixes, etc.
242218
let receiver_ty = match import_candidate {
243219
ImportCandidate::Path(_) => return unfiltered_imports,
244220
ImportCandidate::TraitAssocItem(candidate) | ImportCandidate::TraitMethod(candidate) => {
@@ -325,41 +301,45 @@ impl ImportCandidate {
325301
if sema.resolve_path(path).is_some() {
326302
return None;
327303
}
304+
path_import_candidate(
305+
sema,
306+
path.qualifier(),
307+
NameToImport::Exact(path.segment()?.name_ref()?.to_string()),
308+
)
309+
}
328310

329-
let segment = path.segment()?;
330-
let candidate = if let Some(qualifier) = path.qualifier() {
331-
let qualifier_start = qualifier.syntax().descendants().find_map(ast::NameRef::cast)?;
332-
let qualifier_start_path =
333-
qualifier_start.syntax().ancestors().find_map(ast::Path::cast)?;
334-
if let Some(qualifier_start_resolution) = sema.resolve_path(&qualifier_start_path) {
335-
let qualifier_resolution = if qualifier_start_path == qualifier {
336-
qualifier_start_resolution
337-
} else {
338-
sema.resolve_path(&qualifier)?
339-
};
340-
match qualifier_resolution {
341-
hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path)) => {
342-
ImportCandidate::TraitAssocItem(TraitImportCandidate {
343-
receiver_ty: assoc_item_path.ty(sema.db),
344-
name: NameToImport::Exact(segment.name_ref()?.to_string()),
345-
})
346-
}
347-
_ => return None,
348-
}
349-
} else {
350-
ImportCandidate::Path(PathImportCandidate {
351-
qualifier: Some(qualifier),
352-
name: NameToImport::Exact(qualifier_start.to_string()),
311+
fn for_fuzzy_path(
312+
qualifier: Option<ast::Path>,
313+
fuzzy_name: String,
314+
sema: &Semantics<RootDatabase>,
315+
) -> Option<Self> {
316+
path_import_candidate(sema, qualifier, NameToImport::Fuzzy(fuzzy_name))
317+
}
318+
319+
fn is_trait_candidate(&self) -> bool {
320+
matches!(self, ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_))
321+
}
322+
}
323+
324+
fn path_import_candidate(
325+
sema: &Semantics<RootDatabase>,
326+
qualifier: Option<ast::Path>,
327+
name: NameToImport,
328+
) -> Option<ImportCandidate> {
329+
Some(match qualifier {
330+
Some(qualifier) => match sema.resolve_path(&qualifier) {
331+
None => ImportCandidate::Path(PathImportCandidate {
332+
unresolved_qualifier: Some(qualifier),
333+
name,
334+
}),
335+
Some(hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path))) => {
336+
ImportCandidate::TraitAssocItem(TraitImportCandidate {
337+
receiver_ty: assoc_item_path.ty(sema.db),
338+
name,
353339
})
354340
}
355-
} else {
356-
ImportCandidate::Path(PathImportCandidate {
357-
qualifier: None,
358-
name: NameToImport::Exact(
359-
segment.syntax().descendants().find_map(ast::NameRef::cast)?.to_string(),
360-
),
361-
})
362-
};
363-
Some(candidate)
364-
}
341+
Some(_) => return None,
342+
},
343+
None => ImportCandidate::Path(PathImportCandidate { unresolved_qualifier: None, name }),
344+
})
365345
}

0 commit comments

Comments
 (0)