Skip to content

Commit 11b0126

Browse files
committed
Auto merge of rust-lang#16267 - Veykril:import-map-fix, r=Veykril
internal: Deduplicate some code
2 parents 28e4a9a + d60638e commit 11b0126

File tree

3 files changed

+85
-120
lines changed

3 files changed

+85
-120
lines changed

crates/hir-def/src/import_map.rs

+80-70
Original file line numberDiff line numberDiff line change
@@ -83,29 +83,42 @@ impl ImportMap {
8383
.iter()
8484
// We've only collected items, whose name cannot be tuple field so unwrapping is fine.
8585
.flat_map(|(&item, (info, _))| {
86-
info.iter().enumerate().map(move |(idx, info)| {
87-
(item, info.name.as_str().unwrap().to_ascii_lowercase(), idx as u32)
88-
})
86+
info.iter()
87+
.enumerate()
88+
.map(move |(idx, info)| (item, info.name.to_smol_str(), idx as u32))
8989
})
9090
.collect();
91-
importables.sort_by(|(_, lhs_name, _), (_, rhs_name, _)| lhs_name.cmp(rhs_name));
91+
importables.sort_by(|(_, l_info, _), (_, r_info, _)| {
92+
let lhs_chars = l_info.chars().map(|c| c.to_ascii_lowercase());
93+
let rhs_chars = r_info.chars().map(|c| c.to_ascii_lowercase());
94+
lhs_chars.cmp(rhs_chars)
95+
});
9296
importables.dedup();
9397

9498
// Build the FST, taking care not to insert duplicate values.
9599
let mut builder = fst::MapBuilder::memory();
96-
let iter = importables
100+
let mut iter = importables
97101
.iter()
98102
.enumerate()
99-
.dedup_by(|(_, (_, lhs, _)), (_, (_, rhs, _))| lhs == rhs);
100-
for (start_idx, (_, name, _)) in iter {
101-
let _ = builder.insert(name, start_idx as u64);
103+
.dedup_by(|&(_, (_, lhs, _)), &(_, (_, rhs, _))| lhs.eq_ignore_ascii_case(rhs));
104+
105+
let mut insert = |name: &str, start, end| {
106+
builder.insert(name.to_ascii_lowercase(), ((start as u64) << 32) | end as u64).unwrap()
107+
};
108+
109+
if let Some((mut last, (_, name, _))) = iter.next() {
110+
debug_assert_eq!(last, 0);
111+
let mut last_name = name;
112+
for (next, (_, next_name, _)) in iter {
113+
insert(last_name, last, next);
114+
last = next;
115+
last_name = next_name;
116+
}
117+
insert(last_name, last, importables.len());
102118
}
103119

104-
Arc::new(ImportMap {
105-
item_to_info_map: map,
106-
fst: builder.into_map(),
107-
importables: importables.into_iter().map(|(item, _, idx)| (item, idx)).collect(),
108-
})
120+
let importables = importables.into_iter().map(|(item, _, idx)| (item, idx)).collect();
121+
Arc::new(ImportMap { item_to_info_map: map, fst: builder.into_map(), importables })
109122
}
110123

111124
pub fn import_info_for(&self, item: ItemInNs) -> Option<&[ImportInfo]> {
@@ -266,8 +279,8 @@ impl fmt::Debug for ImportMap {
266279
}
267280

268281
/// A way to match import map contents against the search query.
269-
#[derive(Copy, Clone, Debug)]
270-
enum SearchMode {
282+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
283+
pub enum SearchMode {
271284
/// Import map entry should strictly match the query string.
272285
Exact,
273286
/// Import map entry should contain all letters from the query string,
@@ -277,6 +290,42 @@ enum SearchMode {
277290
Prefix,
278291
}
279292

293+
impl SearchMode {
294+
pub fn check(self, query: &str, case_sensitive: bool, candidate: &str) -> bool {
295+
match self {
296+
SearchMode::Exact if case_sensitive => candidate == query,
297+
SearchMode::Exact => candidate.eq_ignore_ascii_case(&query),
298+
SearchMode::Prefix => {
299+
query.len() <= candidate.len() && {
300+
let prefix = &candidate[..query.len() as usize];
301+
if case_sensitive {
302+
prefix == query
303+
} else {
304+
prefix.eq_ignore_ascii_case(&query)
305+
}
306+
}
307+
}
308+
SearchMode::Fuzzy => {
309+
let mut name = candidate;
310+
query.chars().all(|query_char| {
311+
let m = if case_sensitive {
312+
name.match_indices(query_char).next()
313+
} else {
314+
name.match_indices([query_char, query_char.to_ascii_uppercase()]).next()
315+
};
316+
match m {
317+
Some((index, _)) => {
318+
name = &name[index + 1..];
319+
true
320+
}
321+
None => false,
322+
}
323+
})
324+
}
325+
}
326+
}
327+
}
328+
280329
/// Three possible ways to search for the name in associated and/or other items.
281330
#[derive(Debug, Clone, Copy)]
282331
pub enum AssocSearchMode {
@@ -392,67 +441,28 @@ fn search_maps(
392441
query: &Query,
393442
) -> FxHashSet<ItemInNs> {
394443
let mut res = FxHashSet::default();
395-
while let Some((key, indexed_values)) = stream.next() {
444+
while let Some((_, indexed_values)) = stream.next() {
396445
for &IndexedValue { index: import_map_idx, value } in indexed_values {
397-
let import_map = &import_maps[import_map_idx];
398-
let importables = &import_map.importables[value as usize..];
446+
let end = (value & 0xFFFF_FFFF) as usize;
447+
let start = (value >> 32) as usize;
448+
let ImportMap { item_to_info_map, importables, .. } = &*import_maps[import_map_idx];
449+
let importables = &importables[start as usize..end];
399450

400451
let iter = importables
401452
.iter()
402453
.copied()
403-
.map(|(item, info_idx)| {
404-
let (import_infos, assoc_mode) = &import_map.item_to_info_map[&item];
405-
(item, &import_infos[info_idx as usize], *assoc_mode)
454+
.filter_map(|(item, info_idx)| {
455+
let (import_infos, assoc_mode) = &item_to_info_map[&item];
456+
query
457+
.matches_assoc_mode(*assoc_mode)
458+
.then(|| (item, &import_infos[info_idx as usize]))
406459
})
407-
// we put all entries with the same lowercased name in a row, so stop once we find a
408-
// different name in the importables
409-
// FIXME: Consider putting a range into the value: u64 as (u32, u32)?
410-
.take_while(|&(_, info, _)| {
411-
info.name.to_smol_str().as_bytes().eq_ignore_ascii_case(&key)
412-
})
413-
.filter(|&(_, info, assoc_mode)| {
414-
if !query.matches_assoc_mode(assoc_mode) {
415-
return false;
416-
}
417-
if !query.case_sensitive {
418-
return true;
419-
}
420-
let name = info.name.to_smol_str();
421-
// FIXME: Deduplicate this from ide-db
422-
match query.search_mode {
423-
SearchMode::Exact => !query.case_sensitive || name == query.query,
424-
SearchMode::Prefix => {
425-
query.query.len() <= name.len() && {
426-
let prefix = &name[..query.query.len() as usize];
427-
if query.case_sensitive {
428-
prefix == query.query
429-
} else {
430-
prefix.eq_ignore_ascii_case(&query.query)
431-
}
432-
}
433-
}
434-
SearchMode::Fuzzy => {
435-
let mut name = &*name;
436-
query.query.chars().all(|query_char| {
437-
let m = if query.case_sensitive {
438-
name.match_indices(query_char).next()
439-
} else {
440-
name.match_indices([
441-
query_char,
442-
query_char.to_ascii_uppercase(),
443-
])
444-
.next()
445-
};
446-
match m {
447-
Some((index, _)) => {
448-
name = &name[index + 1..];
449-
true
450-
}
451-
None => false,
452-
}
453-
})
454-
}
455-
}
460+
.filter(|&(_, info)| {
461+
query.search_mode.check(
462+
&query.query,
463+
query.case_sensitive,
464+
&info.name.to_smol_str(),
465+
)
456466
});
457467
res.extend(iter.map(TupleExt::head));
458468
}

crates/hir/src/symbols.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ use crate::{Module, ModuleDef, Semantics};
1818
/// possible.
1919
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2020
pub struct FileSymbol {
21-
// even though name can be derived from the def, we store it for efficiency
2221
pub name: SmolStr,
2322
pub def: ModuleDef,
2423
pub loc: DeclarationLocation,
2524
pub container_name: Option<SmolStr>,
25+
/// Whether this symbol is a doc alias for the original symbol.
2626
pub is_alias: bool,
2727
pub is_assoc: bool,
2828
}
@@ -166,8 +166,6 @@ impl<'a> SymbolCollector<'a> {
166166
// FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily
167167
// for now.
168168
for id in scope.imports() {
169-
let loc = id.import.lookup(self.db.upcast());
170-
loc.id.item_tree(self.db.upcast());
171169
let source = id.import.child_source(self.db.upcast());
172170
let Some(use_tree_src) = source.value.get(id.idx) else { continue };
173171
let Some(rename) = use_tree_src.rename() else { continue };

crates/ide-db/src/symbol_index.rs

+4-47
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use base_db::{
3434
use fst::{self, raw::IndexedValue, Automaton, Streamer};
3535
use hir::{
3636
db::HirDatabase,
37-
import_map::AssocSearchMode,
37+
import_map::{AssocSearchMode, SearchMode},
3838
symbols::{FileSymbol, SymbolCollector},
3939
Crate, Module,
4040
};
@@ -44,22 +44,15 @@ use triomphe::Arc;
4444

4545
use crate::RootDatabase;
4646

47-
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
48-
enum SearchMode {
49-
Fuzzy,
50-
Exact,
51-
Prefix,
52-
}
53-
5447
#[derive(Debug, Clone)]
5548
pub struct Query {
5649
query: String,
5750
lowercased: String,
58-
only_types: bool,
59-
libs: bool,
6051
mode: SearchMode,
6152
assoc_mode: AssocSearchMode,
6253
case_sensitive: bool,
54+
only_types: bool,
55+
libs: bool,
6356
}
6457

6558
impl Query {
@@ -381,43 +374,7 @@ impl Query {
381374
if non_type_for_type_only_query || !self.matches_assoc_mode(symbol.is_assoc) {
382375
continue;
383376
}
384-
// FIXME: Deduplicate this from hir-def
385-
let matches = match self.mode {
386-
SearchMode::Exact if self.case_sensitive => symbol.name == self.query,
387-
SearchMode::Exact => symbol.name.eq_ignore_ascii_case(&self.query),
388-
SearchMode::Prefix => {
389-
self.query.len() <= symbol.name.len() && {
390-
let prefix = &symbol.name[..self.query.len() as usize];
391-
if self.case_sensitive {
392-
prefix == self.query
393-
} else {
394-
prefix.eq_ignore_ascii_case(&self.query)
395-
}
396-
}
397-
}
398-
SearchMode::Fuzzy => {
399-
let mut name = &*symbol.name;
400-
self.query.chars().all(|query_char| {
401-
let m = if self.case_sensitive {
402-
name.match_indices(query_char).next()
403-
} else {
404-
name.match_indices([
405-
query_char,
406-
query_char.to_ascii_uppercase(),
407-
])
408-
.next()
409-
};
410-
match m {
411-
Some((index, _)) => {
412-
name = &name[index + 1..];
413-
true
414-
}
415-
None => false,
416-
}
417-
})
418-
}
419-
};
420-
if matches {
377+
if self.mode.check(&self.query, self.case_sensitive, &symbol.name) {
421378
cb(symbol);
422379
}
423380
}

0 commit comments

Comments
 (0)