Skip to content

Commit 21913d0

Browse files
bors[bot]SomeoneToIgnorematklad
authored
Merge #7873 #7933
7873: Consider unresolved qualifiers during flyimport r=matklad a=SomeoneToIgnore Closes #7679 Takes unresolved qualifiers into account, providing better completions (or none, if the path is resolved or do not match). Does not handle cases when both path qualifier and some trait has to be imported: there are many extra issues with those (such as overlapping imports, for instance) that will require large diffs to address. Also does not do a fuzzy search on qualifier, that requires some adjustments in `import_map` for better queries and changes to the default replace range which also seems relatively big to include here. ![qualifier_completion](https://user-images.githubusercontent.com/2690773/110040808-0af8dc00-7d4c-11eb-83db-65af94e843bb.gif) 7933: Improve compilation speed r=matklad a=matklad bors r+ 🤖 Co-authored-by: Kirill Bulatov <mail4score@gmail.com> Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
3 parents 5e0e530 + 778deb3 + 867fdf8 commit 21913d0

File tree

18 files changed

+847
-380
lines changed

18 files changed

+847
-380
lines changed

crates/hir/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,7 @@ pub enum AssocItem {
11141114
Const(Const),
11151115
TypeAlias(TypeAlias),
11161116
}
1117+
#[derive(Debug)]
11171118
pub enum AssocItemContainer {
11181119
Trait(Trait),
11191120
Impl(Impl),
@@ -2136,6 +2137,16 @@ impl ScopeDef {
21362137
}
21372138
}
21382139

2140+
impl From<ItemInNs> for ScopeDef {
2141+
fn from(item: ItemInNs) -> Self {
2142+
match item {
2143+
ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()),
2144+
ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()),
2145+
ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()),
2146+
}
2147+
}
2148+
}
2149+
21392150
pub trait HasVisibility {
21402151
fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
21412152
fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {

crates/ide/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,6 @@ impl Analysis {
478478
position: FilePosition,
479479
full_import_path: &str,
480480
imported_name: String,
481-
import_for_trait_assoc_item: bool,
482481
) -> Cancelable<Vec<TextEdit>> {
483482
Ok(self
484483
.with_db(|db| {
@@ -488,7 +487,6 @@ impl Analysis {
488487
position,
489488
full_import_path,
490489
imported_name,
491-
import_for_trait_assoc_item,
492490
)
493491
})?
494492
.unwrap_or_default())

crates/ide_assists/src/handlers/auto_import.rs

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use ide_db::helpers::{
22
import_assets::{ImportAssets, ImportCandidate},
33
insert_use::{insert_use, ImportScope},
4-
mod_path_to_ast,
4+
item_name, mod_path_to_ast,
55
};
66
use syntax::{ast, AstNode, SyntaxNode};
77

@@ -92,14 +92,19 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
9292
let range = ctx.sema.original_range(&syntax_under_caret).range;
9393
let group = import_group_message(import_assets.import_candidate());
9494
let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?;
95-
for (import, _) in proposed_imports {
95+
for import in proposed_imports {
96+
let name = match item_name(ctx.db(), import.original_item) {
97+
Some(name) => name,
98+
None => continue,
99+
};
96100
acc.add_group(
97101
&group,
98102
AssistId("auto_import", AssistKind::QuickFix),
99-
format!("Import `{}`", &import),
103+
format!("Import `{}`", name),
100104
range,
101105
|builder| {
102-
let rewriter = insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use);
106+
let rewriter =
107+
insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use);
103108
builder.rewrite(rewriter);
104109
},
105110
);
@@ -125,10 +130,10 @@ fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel {
125130
let name = match import_candidate {
126131
ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
127132
ImportCandidate::TraitAssocItem(candidate) => {
128-
format!("Import a trait for item {}", candidate.name.text())
133+
format!("Import a trait for item {}", candidate.assoc_item_name.text())
129134
}
130135
ImportCandidate::TraitMethod(candidate) => {
131-
format!("Import a trait for method {}", candidate.name.text())
136+
format!("Import a trait for method {}", candidate.assoc_item_name.text())
132137
}
133138
};
134139
GroupLabel(name)
@@ -220,41 +225,6 @@ mod tests {
220225
);
221226
}
222227

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-
258228
#[test]
259229
fn applicable_when_found_multiple_imports() {
260230
check_assist(

crates/ide_assists/src/handlers/qualify_path.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use std::iter;
22

33
use hir::AsAssocItem;
4-
use ide_db::helpers::{import_assets::ImportCandidate, mod_path_to_ast};
4+
use ide_db::helpers::{
5+
import_assets::{ImportCandidate, LocatedImport},
6+
item_name, mod_path_to_ast,
7+
};
58
use ide_db::RootDatabase;
69
use syntax::{
710
ast,
@@ -71,17 +74,17 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
7174
};
7275

7376
let group_label = group_label(candidate);
74-
for (import, item) in proposed_imports {
77+
for import in proposed_imports {
7578
acc.add_group(
7679
&group_label,
7780
AssistId("qualify_path", AssistKind::QuickFix),
78-
label(candidate, &import),
81+
label(ctx.db(), candidate, &import),
7982
range,
8083
|builder| {
8184
qualify_candidate.qualify(
8285
|replace_with: String| builder.replace(range, replace_with),
83-
import,
84-
item,
86+
&import.import_path,
87+
import.item_to_import,
8588
)
8689
},
8790
);
@@ -97,8 +100,13 @@ enum QualifyCandidate<'db> {
97100
}
98101

99102
impl QualifyCandidate<'_> {
100-
fn qualify(&self, mut replacer: impl FnMut(String), import: hir::ModPath, item: hir::ItemInNs) {
101-
let import = mod_path_to_ast(&import);
103+
fn qualify(
104+
&self,
105+
mut replacer: impl FnMut(String),
106+
import: &hir::ModPath,
107+
item: hir::ItemInNs,
108+
) {
109+
let import = mod_path_to_ast(import);
102110
match self {
103111
QualifyCandidate::QualifierStart(segment, generics) => {
104112
let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
@@ -183,23 +191,29 @@ fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
183191
fn group_label(candidate: &ImportCandidate) -> GroupLabel {
184192
let name = match candidate {
185193
ImportCandidate::Path(it) => &it.name,
186-
ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name,
194+
ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => {
195+
&it.assoc_item_name
196+
}
187197
}
188198
.text();
189199
GroupLabel(format!("Qualify {}", name))
190200
}
191201

192-
fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String {
202+
fn label(db: &RootDatabase, candidate: &ImportCandidate, import: &LocatedImport) -> String {
203+
let display_path = match item_name(db, import.original_item) {
204+
Some(display_path) => display_path.to_string(),
205+
None => "{unknown}".to_string(),
206+
};
193207
match candidate {
194208
ImportCandidate::Path(candidate) => {
195209
if candidate.qualifier.is_some() {
196-
format!("Qualify with `{}`", &import)
210+
format!("Qualify with `{}`", display_path)
197211
} else {
198-
format!("Qualify as `{}`", &import)
212+
format!("Qualify as `{}`", display_path)
199213
}
200214
}
201-
ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import),
202-
ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import),
215+
ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", display_path),
216+
ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", display_path),
203217
}
204218
}
205219

crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
use hir::ModuleDef;
12
use ide_db::helpers::mod_path_to_ast;
2-
use ide_db::imports_locator;
3+
use ide_db::items_locator;
34
use itertools::Itertools;
45
use syntax::{
56
ast::{self, make, AstNode, NameOwner},
@@ -64,22 +65,20 @@ pub(crate) fn replace_derive_with_manual_impl(
6465
let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
6566
let current_crate = current_module.krate();
6667

67-
let found_traits = imports_locator::find_exact_imports(
68-
&ctx.sema,
69-
current_crate,
70-
trait_token.text().to_string(),
71-
)
72-
.filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
73-
either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
74-
_ => None,
75-
})
76-
.flat_map(|trait_| {
77-
current_module
78-
.find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
79-
.as_ref()
80-
.map(mod_path_to_ast)
81-
.zip(Some(trait_))
82-
});
68+
let found_traits =
69+
items_locator::with_exact_name(&ctx.sema, current_crate, trait_token.text().to_string())
70+
.into_iter()
71+
.filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) {
72+
ModuleDef::Trait(trait_) => Some(trait_),
73+
_ => None,
74+
})
75+
.flat_map(|trait_| {
76+
current_module
77+
.find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
78+
.as_ref()
79+
.map(mod_path_to_ast)
80+
.zip(Some(trait_))
81+
});
8382

8483
let mut no_traits_found = true;
8584
for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {

0 commit comments

Comments
 (0)