Skip to content

Commit a631108

Browse files
Do not query item search by name eagerly
1 parent 81961dc commit a631108

File tree

4 files changed

+200
-222
lines changed

4 files changed

+200
-222
lines changed

crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use hir::ModuleDef;
2-
use ide_db::helpers::mod_path_to_ast;
2+
use ide_db::helpers::{import_assets::NameToImport, mod_path_to_ast};
33
use ide_db::items_locator;
44
use itertools::Itertools;
55
use syntax::{
@@ -65,20 +65,25 @@ pub(crate) fn replace_derive_with_manual_impl(
6565
let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
6666
let current_crate = current_module.krate();
6767

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-
});
68+
let found_traits = items_locator::locate_for_name(
69+
&ctx.sema,
70+
current_crate,
71+
NameToImport::Exact(trait_token.text().to_string()),
72+
items_locator::AssocItemSearch::Exclude,
73+
None,
74+
)
75+
.into_iter()
76+
.filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) {
77+
ModuleDef::Trait(trait_) => Some(trait_),
78+
_ => None,
79+
})
80+
.flat_map(|trait_| {
81+
current_module
82+
.find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
83+
.as_ref()
84+
.map(mod_path_to_ast)
85+
.zip(Some(trait_))
86+
});
8287

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

crates/ide_completion/src/lib.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ mod completions;
1414
use completions::flyimport::position_for_import;
1515
use ide_db::{
1616
base_db::FilePosition,
17-
helpers::{import_assets::LocatedImport, insert_use::ImportScope},
17+
helpers::{
18+
import_assets::{LocatedImport, NameToImport},
19+
insert_use::ImportScope,
20+
},
1821
items_locator, RootDatabase,
1922
};
2023
use text_edit::TextEdit;
@@ -149,15 +152,20 @@ pub fn resolve_completion_edits(
149152
let current_module = ctx.sema.scope(position_for_import).module()?;
150153
let current_crate = current_module.krate();
151154

152-
let (import_path, item_to_import) =
153-
items_locator::with_exact_name(&ctx.sema, current_crate, imported_name)
154-
.into_iter()
155-
.filter_map(|candidate| {
156-
current_module
157-
.find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
158-
.zip(Some(candidate))
159-
})
160-
.find(|(mod_path, _)| mod_path.to_string() == full_import_path)?;
155+
let (import_path, item_to_import) = items_locator::locate_for_name(
156+
&ctx.sema,
157+
current_crate,
158+
NameToImport::Exact(imported_name),
159+
items_locator::AssocItemSearch::Include,
160+
None,
161+
)
162+
.into_iter()
163+
.filter_map(|candidate| {
164+
current_module
165+
.find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
166+
.zip(Some(candidate))
167+
})
168+
.find(|(mod_path, _)| mod_path.to_string() == full_import_path)?;
161169
let import =
162170
LocatedImport::new(import_path.clone(), item_to_import, item_to_import, Some(import_path));
163171

crates/ide_db/src/helpers/import_assets.rs

Lines changed: 89 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub struct FirstSegmentUnresolved {
6161
}
6262

6363
/// A name that will be used during item lookups.
64-
#[derive(Debug)]
64+
#[derive(Debug, Clone)]
6565
pub enum NameToImport {
6666
/// Requires items with names that exactly match the given string, case-sensitive.
6767
Exact(String),
@@ -201,131 +201,96 @@ impl ImportAssets {
201201
sema: &Semantics<RootDatabase>,
202202
prefixed: Option<PrefixKind>,
203203
) -> Vec<LocatedImport> {
204-
let items_with_candidate_name = match self.name_to_import() {
205-
NameToImport::Exact(exact_name) => items_locator::with_exact_name(
206-
sema,
207-
self.module_with_candidate.krate(),
208-
exact_name.clone(),
209-
),
210-
// FIXME: ideally, we should avoid using `fst` for seacrhing trait imports for assoc items:
211-
// instead, we need to look up all trait impls for a certain struct and search through them only
212-
// see https://github.com/rust-analyzer/rust-analyzer/pull/7293#issuecomment-761585032
213-
// and https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Blanket.20trait.20impls.20lookup
214-
// for the details
215-
NameToImport::Fuzzy(fuzzy_name) => {
216-
let (assoc_item_search, limit) = if self.import_candidate.is_trait_candidate() {
217-
(AssocItemSearch::AssocItemsOnly, None)
218-
} else {
219-
(AssocItemSearch::Include, Some(DEFAULT_QUERY_SEARCH_LIMIT))
220-
};
221-
222-
items_locator::with_similar_name(
223-
sema,
224-
self.module_with_candidate.krate(),
225-
fuzzy_name.clone(),
226-
assoc_item_search,
227-
limit,
228-
)
229-
}
230-
};
204+
let _p = profile::span("import_assets::search_for");
231205

232206
let scope_definitions = self.scope_definitions(sema);
233-
self.applicable_defs(sema.db, prefixed, items_with_candidate_name)
234-
.into_iter()
235-
.filter(|import| import.import_path.len() > 1)
236-
.filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import)))
237-
.sorted_by_key(|import| import.import_path.clone())
238-
.collect()
239-
}
240-
241-
fn scope_definitions(&self, sema: &Semantics<RootDatabase>) -> FxHashSet<ScopeDef> {
242-
let mut scope_definitions = FxHashSet::default();
243-
sema.scope(&self.candidate_node).process_all_names(&mut |_, scope_def| {
244-
scope_definitions.insert(scope_def);
245-
});
246-
scope_definitions
247-
}
248-
249-
fn name_to_import(&self) -> &NameToImport {
250-
match &self.import_candidate {
251-
ImportCandidate::Path(candidate) => &candidate.name,
252-
ImportCandidate::TraitAssocItem(candidate)
253-
| ImportCandidate::TraitMethod(candidate) => &candidate.assoc_item_name,
254-
}
255-
}
256-
257-
fn applicable_defs(
258-
&self,
259-
db: &RootDatabase,
260-
prefixed: Option<PrefixKind>,
261-
items_with_candidate_name: FxHashSet<ItemInNs>,
262-
) -> FxHashSet<LocatedImport> {
263-
let _p = profile::span("import_assets::applicable_defs");
264207
let current_crate = self.module_with_candidate.krate();
265-
266208
let mod_path = |item| {
267-
get_mod_path(db, item_for_path_search(db, item)?, &self.module_with_candidate, prefixed)
209+
get_mod_path(
210+
sema.db,
211+
item_for_path_search(sema.db, item)?,
212+
&self.module_with_candidate,
213+
prefixed,
214+
)
268215
};
269216

270217
match &self.import_candidate {
271218
ImportCandidate::Path(path_candidate) => {
272-
path_applicable_imports(db, path_candidate, mod_path, items_with_candidate_name)
219+
path_applicable_imports(sema, current_crate, path_candidate, mod_path)
220+
}
221+
ImportCandidate::TraitAssocItem(trait_candidate) => {
222+
trait_applicable_items(sema, current_crate, trait_candidate, true, mod_path)
223+
}
224+
ImportCandidate::TraitMethod(trait_candidate) => {
225+
trait_applicable_items(sema, current_crate, trait_candidate, false, mod_path)
273226
}
274-
ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items(
275-
db,
276-
current_crate,
277-
trait_candidate,
278-
true,
279-
mod_path,
280-
items_with_candidate_name,
281-
),
282-
ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items(
283-
db,
284-
current_crate,
285-
trait_candidate,
286-
false,
287-
mod_path,
288-
items_with_candidate_name,
289-
),
290227
}
228+
.into_iter()
229+
.filter(|import| import.import_path.len() > 1)
230+
.filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import)))
231+
.sorted_by_key(|import| import.import_path.clone())
232+
.collect()
233+
}
234+
235+
fn scope_definitions(&self, sema: &Semantics<RootDatabase>) -> FxHashSet<ScopeDef> {
236+
let _p = profile::span("import_assets::scope_definitions");
237+
let mut scope_definitions = FxHashSet::default();
238+
sema.scope(&self.candidate_node).process_all_names(&mut |_, scope_def| {
239+
scope_definitions.insert(scope_def);
240+
});
241+
scope_definitions
291242
}
292243
}
293244

294245
fn path_applicable_imports(
295-
db: &RootDatabase,
246+
sema: &Semantics<RootDatabase>,
247+
current_crate: Crate,
296248
path_candidate: &PathImportCandidate,
297249
mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
298-
items_with_candidate_name: FxHashSet<ItemInNs>,
299250
) -> FxHashSet<LocatedImport> {
300251
let _p = profile::span("import_assets::path_applicable_imports");
301252

302-
let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier {
253+
match &path_candidate.qualifier {
303254
None => {
304-
return items_with_candidate_name
305-
.into_iter()
306-
.filter_map(|item| {
307-
if item_as_assoc(db, item).is_some() {
308-
// unqualified assoc items are not valid syntax
309-
return None;
310-
}
311-
312-
let mod_path = mod_path(item)?;
313-
Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path)))
314-
})
315-
.collect();
255+
items_locator::locate_for_name(
256+
sema,
257+
current_crate,
258+
path_candidate.name.clone(),
259+
// unqualified assoc items are not valid syntax
260+
AssocItemSearch::Exclude,
261+
Some(DEFAULT_QUERY_SEARCH_LIMIT),
262+
)
263+
.into_iter()
264+
.filter_map(|item| {
265+
let mod_path = mod_path(item)?;
266+
Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path)))
267+
})
268+
.collect()
316269
}
317-
Some(first_segment_unresolved) => (
318-
first_segment_unresolved.fist_segment.to_string(),
319-
path_to_string_stripping_turbo_fish(&first_segment_unresolved.full_qualifier),
320-
),
321-
};
322-
323-
items_with_candidate_name
324-
.into_iter()
325-
.filter_map(|item| {
326-
import_for_item(db, mod_path, &unresolved_first_segment, &unresolved_qualifier, item)
327-
})
328-
.collect()
270+
Some(first_segment_unresolved) => {
271+
let unresolved_qualifier =
272+
path_to_string_stripping_turbo_fish(&first_segment_unresolved.full_qualifier);
273+
let unresolved_first_segment = first_segment_unresolved.fist_segment.text();
274+
items_locator::locate_for_name(
275+
sema,
276+
current_crate,
277+
path_candidate.name.clone(),
278+
AssocItemSearch::Include,
279+
Some(DEFAULT_QUERY_SEARCH_LIMIT),
280+
)
281+
.into_iter()
282+
.filter_map(|item| {
283+
import_for_item(
284+
sema.db,
285+
mod_path,
286+
unresolved_first_segment,
287+
&unresolved_qualifier,
288+
item,
289+
)
290+
})
291+
.collect()
292+
}
293+
}
329294
}
330295

331296
fn import_for_item(
@@ -440,25 +405,32 @@ fn module_with_segment_name(
440405
}
441406

442407
fn trait_applicable_items(
443-
db: &RootDatabase,
408+
sema: &Semantics<RootDatabase>,
444409
current_crate: Crate,
445410
trait_candidate: &TraitImportCandidate,
446411
trait_assoc_item: bool,
447412
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
448-
items_with_candidate_name: FxHashSet<ItemInNs>,
449413
) -> FxHashSet<LocatedImport> {
450414
let _p = profile::span("import_assets::trait_applicable_items");
451-
let mut required_assoc_items = FxHashSet::default();
452415

453-
let trait_candidates = items_with_candidate_name
454-
.into_iter()
455-
.filter_map(|input| item_as_assoc(db, input))
456-
.filter_map(|assoc| {
457-
let assoc_item_trait = assoc.containing_trait(db)?;
458-
required_assoc_items.insert(assoc);
459-
Some(assoc_item_trait.into())
460-
})
461-
.collect();
416+
let db = sema.db;
417+
418+
let mut required_assoc_items = FxHashSet::default();
419+
let trait_candidates = items_locator::locate_for_name(
420+
sema,
421+
current_crate,
422+
trait_candidate.assoc_item_name.clone(),
423+
AssocItemSearch::AssocItemsOnly,
424+
Some(DEFAULT_QUERY_SEARCH_LIMIT),
425+
)
426+
.into_iter()
427+
.filter_map(|input| item_as_assoc(db, input))
428+
.filter_map(|assoc| {
429+
let assoc_item_trait = assoc.containing_trait(db)?;
430+
required_assoc_items.insert(assoc);
431+
Some(assoc_item_trait.into())
432+
})
433+
.collect();
462434

463435
let mut located_imports = FxHashSet::default();
464436

@@ -567,10 +539,6 @@ impl ImportCandidate {
567539
) -> Option<Self> {
568540
path_import_candidate(sema, qualifier, NameToImport::Fuzzy(fuzzy_name))
569541
}
570-
571-
fn is_trait_candidate(&self) -> bool {
572-
matches!(self, ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_))
573-
}
574542
}
575543

576544
fn path_import_candidate(

0 commit comments

Comments
 (0)