Skip to content

Commit

Permalink
Auto merge of #16261 - Veykril:import-map-fix, r=Veykril
Browse files Browse the repository at this point in the history
internal: Move query limits to the caller

Prior we calculated up to `limit` entries from a query, then filtered from that leaving us with less entries than the limit in some cases (which might give odd completion behavior due to items disappearing). This changes it so we filter before checking the limit.
  • Loading branch information
bors committed Jan 4, 2024
2 parents a795f48 + 2666349 commit c84352a
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 124 deletions.
65 changes: 23 additions & 42 deletions crates/hir-def/src/import_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ pub struct Query {
search_mode: SearchMode,
assoc_mode: AssocSearchMode,
case_sensitive: bool,
limit: usize,
}

impl Query {
Expand All @@ -307,7 +306,6 @@ impl Query {
search_mode: SearchMode::Exact,
assoc_mode: AssocSearchMode::Include,
case_sensitive: false,
limit: usize::MAX,
}
}

Expand All @@ -329,11 +327,6 @@ impl Query {
Self { assoc_mode, ..self }
}

/// Limits the returned number of items to `limit`.
pub fn limit(self, limit: usize) -> Self {
Self { limit, ..self }
}

/// Respect casing of the query string when matching.
pub fn case_sensitive(self) -> Self {
Self { case_sensitive: true, ..self }
Expand Down Expand Up @@ -413,6 +406,7 @@ fn search_maps(
})
// we put all entries with the same lowercased name in a row, so stop once we find a
// different name in the importables
// FIXME: Consider putting a range into the value: u64 as (u32, u32)?
.take_while(|&(_, info, _)| {
info.name.to_smol_str().as_bytes().eq_ignore_ascii_case(&key)
})
Expand All @@ -424,13 +418,32 @@ fn search_maps(
return true;
}
let name = info.name.to_smol_str();
// FIXME: Deduplicate this from ide-db
match query.search_mode {
SearchMode::Exact => name == query.query,
SearchMode::Prefix => name.starts_with(&query.query),
SearchMode::Exact => !query.case_sensitive || name == query.query,
SearchMode::Prefix => {
query.query.len() <= name.len() && {
let prefix = &name[..query.query.len() as usize];
if query.case_sensitive {
prefix == query.query
} else {
prefix.eq_ignore_ascii_case(&query.query)
}
}
}
SearchMode::Fuzzy => {
let mut name = &*name;
query.query.chars().all(|query_char| {
match name.match_indices(query_char).next() {
let m = if query.case_sensitive {
name.match_indices(query_char).next()
} else {
name.match_indices([
query_char,
query_char.to_ascii_uppercase(),
])
.next()
};
match m {
Some((index, _)) => {
name = &name[index + 1..];
true
Expand All @@ -442,10 +455,6 @@ fn search_maps(
}
});
res.extend(iter.map(TupleExt::head));

if res.len() >= query.limit {
return res;
}
}
}

Expand Down Expand Up @@ -1015,32 +1024,4 @@ pub mod fmt {
"#]],
);
}

#[test]
fn search_limit() {
check_search(
r#"
//- /main.rs crate:main deps:dep
//- /dep.rs crate:dep
pub mod fmt {
pub trait Display {
fn fmt();
}
}
#[macro_export]
macro_rules! Fmt {
() => {};
}
pub struct Fmt;
pub fn format() {}
pub fn no() {}
"#,
"main",
Query::new("".to_string()).fuzzy().limit(1),
expect![[r#"
dep::fmt::Display (t)
"#]],
);
}
}
2 changes: 1 addition & 1 deletion crates/hir/src/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl<'a> SymbolCollector<'a> {
}

// Record renamed imports.
// In case it imports multiple items under different namespaces we just pick one arbitrarily
// FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily
// for now.
for id in scope.imports() {
let loc = id.import.lookup(self.db.upcast());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ pub(crate) fn replace_derive_with_manual_impl(
current_crate,
NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
items_locator::AssocSearchMode::Exclude,
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
)
.filter_map(|item| match item.as_module_def()? {
ModuleDef::Trait(trait_) => Some(trait_),
Expand Down
1 change: 0 additions & 1 deletion crates/ide-completion/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ pub fn resolve_completion_edits(
current_crate,
NameToImport::exact_case_sensitive(imported_name),
items_locator::AssocSearchMode::Include,
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
);
let import = items_with_name
.filter_map(|candidate| {
Expand Down
6 changes: 3 additions & 3 deletions crates/ide-db/src/imports/import_assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,22 +333,22 @@ fn path_applicable_imports(
//
// see also an ignored test under FIXME comment in the qualify_path.rs module
AssocSearchMode::Exclude,
Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
)
.filter_map(|item| {
let mod_path = mod_path(item)?;
Some(LocatedImport::new(mod_path, item, item))
})
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
.collect()
}
Some(qualifier) => items_locator::items_with_name(
sema,
current_crate,
path_candidate.name.clone(),
AssocSearchMode::Include,
Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
)
.filter_map(|item| import_for_item(sema.db, mod_path, &qualifier, item))
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
.collect(),
}
}
Expand Down Expand Up @@ -505,7 +505,6 @@ fn trait_applicable_items(
current_crate,
trait_candidate.assoc_item_name.clone(),
AssocSearchMode::AssocItemsOnly,
Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
)
.filter_map(|input| item_as_assoc(db, input))
.filter_map(|assoc| {
Expand All @@ -517,6 +516,7 @@ fn trait_applicable_items(
Some(assoc_item_trait.into())
}
})
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
.collect();

let mut located_imports = FxHashSet::default();
Expand Down
37 changes: 12 additions & 25 deletions crates/ide-db/src/items_locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,24 @@ pub fn items_with_name<'a>(
krate: Crate,
name: NameToImport,
assoc_item_search: AssocSearchMode,
limit: Option<usize>,
) -> impl Iterator<Item = ItemInNs> + 'a {
let _p = profile::span("items_with_name").detail(|| {
format!(
"Name: {}, crate: {:?}, assoc items: {:?}, limit: {:?}",
"Name: {}, crate: {:?}, assoc items: {:?}",
name.text(),
assoc_item_search,
krate.display_name(sema.db).map(|name| name.to_string()),
limit,
)
});

let prefix = matches!(name, NameToImport::Prefix(..));
let (mut local_query, mut external_query) = match name {
let (local_query, external_query) = match name {
NameToImport::Prefix(exact_name, case_sensitive)
| NameToImport::Exact(exact_name, case_sensitive) => {
let mut local_query = symbol_index::Query::new(exact_name.clone());
local_query.assoc_search_mode(assoc_item_search);
let mut external_query =
// import_map::Query::new(exact_name).assoc_search_mode(assoc_item_search);
import_map::Query::new(exact_name);
import_map::Query::new(exact_name).assoc_search_mode(assoc_item_search);
if prefix {
local_query.prefix();
external_query = external_query.prefix();
Expand All @@ -55,6 +53,7 @@ pub fn items_with_name<'a>(
NameToImport::Fuzzy(fuzzy_search_string, case_sensitive) => {
let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone());
local_query.fuzzy();
local_query.assoc_search_mode(assoc_item_search);

let mut external_query = import_map::Query::new(fuzzy_search_string.clone())
.fuzzy()
Expand All @@ -69,18 +68,12 @@ pub fn items_with_name<'a>(
}
};

if let Some(limit) = limit {
external_query = external_query.limit(limit);
local_query.limit(limit);
}

find_items(sema, krate, assoc_item_search, local_query, external_query)
find_items(sema, krate, local_query, external_query)
}

fn find_items<'a>(
sema: &'a Semantics<'_, RootDatabase>,
krate: Crate,
assoc_item_search: AssocSearchMode,
local_query: symbol_index::Query,
external_query: import_map::Query,
) -> impl Iterator<Item = ItemInNs> + 'a {
Expand All @@ -98,18 +91,12 @@ fn find_items<'a>(
});

// Query the local crate using the symbol index.
let local_results = local_query
.search(&symbol_index::crate_symbols(db, krate))
.into_iter()
.filter(move |candidate| match assoc_item_search {
AssocSearchMode::Include => true,
AssocSearchMode::Exclude => !candidate.is_assoc,
AssocSearchMode::AssocItemsOnly => candidate.is_assoc,
})
.map(|local_candidate| match local_candidate.def {
let mut local_results = Vec::new();
local_query.search(&symbol_index::crate_symbols(db, krate), |local_candidate| {
local_results.push(match local_candidate.def {
hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
def => ItemInNs::from(def),
});

external_importables.chain(local_results)
})
});
local_results.into_iter().chain(external_importables)
}
Loading

0 comments on commit c84352a

Please sign in to comment.