mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 06:41:48 +00:00
Add associated data into fst
This commit is contained in:
parent
1bfc3a50c0
commit
63d83fa385
1 changed files with 45 additions and 49 deletions
|
@ -7,9 +7,7 @@ use fst::{self, Streamer};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
use indexmap::{map::Entry, IndexMap};
|
use indexmap::{map::Entry, IndexMap};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
|
use rustc_hash::{FxHashSet, FxHasher};
|
||||||
use smallvec::SmallVec;
|
|
||||||
use syntax::SmolStr;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId,
|
db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId,
|
||||||
|
@ -25,6 +23,8 @@ pub struct ImportInfo {
|
||||||
pub path: ImportPath,
|
pub path: ImportPath,
|
||||||
/// The module containing this item.
|
/// The module containing this item.
|
||||||
pub container: ModuleId,
|
pub container: ModuleId,
|
||||||
|
/// Whether the import is a trait associated item or not.
|
||||||
|
pub is_assoc_item: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
@ -64,10 +64,6 @@ pub struct ImportMap {
|
||||||
/// the index of the first one.
|
/// the index of the first one.
|
||||||
importables: Vec<ItemInNs>,
|
importables: Vec<ItemInNs>,
|
||||||
fst: fst::Map<Vec<u8>>,
|
fst: fst::Map<Vec<u8>>,
|
||||||
|
|
||||||
/// Maps names of associated items to the item's ID. Only includes items whose defining trait is
|
|
||||||
/// exported.
|
|
||||||
assoc_map: FxHashMap<SmolStr, SmallVec<[AssocItemId; 1]>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImportMap {
|
impl ImportMap {
|
||||||
|
@ -108,14 +104,22 @@ impl ImportMap {
|
||||||
|
|
||||||
for item in per_ns.iter_items() {
|
for item in per_ns.iter_items() {
|
||||||
let path = mk_path();
|
let path = mk_path();
|
||||||
|
let path_len = path.len();
|
||||||
|
let import_info = ImportInfo { path, container: module, is_assoc_item: false };
|
||||||
|
|
||||||
|
// If we've added a path to a trait, add the trait's associated items to the assoc map.
|
||||||
|
if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
|
||||||
|
import_map.collect_trait_assoc_items(db, tr, &import_info);
|
||||||
|
}
|
||||||
|
|
||||||
match import_map.map.entry(item) {
|
match import_map.map.entry(item) {
|
||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
entry.insert(ImportInfo { path, container: module });
|
entry.insert(import_info);
|
||||||
}
|
}
|
||||||
Entry::Occupied(mut entry) => {
|
Entry::Occupied(mut entry) => {
|
||||||
// If the new path is shorter, prefer that one.
|
// If the new path is shorter, prefer that one.
|
||||||
if path.len() < entry.get().path.len() {
|
if path_len < entry.get().path.len() {
|
||||||
*entry.get_mut() = ImportInfo { path, container: module };
|
*entry.get_mut() = import_info;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -128,11 +132,6 @@ impl ImportMap {
|
||||||
if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
|
if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
|
||||||
worklist.push((mod_id, mk_path()));
|
worklist.push((mod_id, mk_path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've added a path to a trait, add the trait's methods to the method map.
|
|
||||||
if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
|
|
||||||
import_map.collect_trait_methods(db, tr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,12 +152,10 @@ impl ImportMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = last_batch_start;
|
let key = fst_path(&importables[last_batch_start].1.path);
|
||||||
|
builder.insert(key, last_batch_start as u64).unwrap();
|
||||||
|
|
||||||
last_batch_start = idx + 1;
|
last_batch_start = idx + 1;
|
||||||
|
|
||||||
let key = fst_path(&importables[start].1.path);
|
|
||||||
|
|
||||||
builder.insert(key, start as u64).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap();
|
import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap();
|
||||||
|
@ -176,10 +173,22 @@ impl ImportMap {
|
||||||
self.map.get(&item)
|
self.map.get(&item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_trait_methods(&mut self, db: &dyn DefDatabase, tr: TraitId) {
|
fn collect_trait_assoc_items(
|
||||||
let data = db.trait_data(tr);
|
&mut self,
|
||||||
for (name, item) in data.items.iter() {
|
db: &dyn DefDatabase,
|
||||||
self.assoc_map.entry(name.to_string().into()).or_default().push(*item);
|
tr: TraitId,
|
||||||
|
import_info: &ImportInfo,
|
||||||
|
) {
|
||||||
|
for (assoc_item_name, item) in db.trait_data(tr).items.iter() {
|
||||||
|
let assoc_item = ItemInNs::Types(match item.clone() {
|
||||||
|
AssocItemId::FunctionId(f) => f.into(),
|
||||||
|
AssocItemId::ConstId(c) => c.into(),
|
||||||
|
AssocItemId::TypeAliasId(t) => t.into(),
|
||||||
|
});
|
||||||
|
let mut assoc_item_info = import_info.to_owned();
|
||||||
|
assoc_item_info.path.segments.push(assoc_item_name.to_owned());
|
||||||
|
assoc_item_info.is_assoc_item = true;
|
||||||
|
self.map.insert(assoc_item, assoc_item_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,11 +313,11 @@ impl Query {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool {
|
fn import_matches_query(import: &ImportInfo, query: &Query, enforce_lowercase: bool) -> bool {
|
||||||
let mut input = if query.name_only {
|
let mut input = if import.is_assoc_item || query.name_only {
|
||||||
input_path.segments.last().unwrap().to_string()
|
import.path.segments.last().unwrap().to_string()
|
||||||
} else {
|
} else {
|
||||||
input_path.to_string()
|
import.path.to_string()
|
||||||
};
|
};
|
||||||
if enforce_lowercase || !query.case_sensitive {
|
if enforce_lowercase || !query.case_sensitive {
|
||||||
input.make_ascii_lowercase();
|
input.make_ascii_lowercase();
|
||||||
|
@ -366,13 +375,13 @@ pub fn search_dependencies<'a>(
|
||||||
let import_map = &import_maps[indexed_value.index];
|
let import_map = &import_maps[indexed_value.index];
|
||||||
let importables = &import_map.importables[indexed_value.value as usize..];
|
let importables = &import_map.importables[indexed_value.value as usize..];
|
||||||
|
|
||||||
// Path shared by the importable items in this group.
|
let common_importable_data = &import_map.map[&importables[0]];
|
||||||
let common_importables_path = &import_map.map[&importables[0]].path;
|
if !import_matches_query(common_importable_data, &query, true) {
|
||||||
if !contains_query(&query, common_importables_path, true) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let common_importables_path_fst = fst_path(common_importables_path);
|
// Path shared by the importable items in this group.
|
||||||
|
let common_importables_path_fst = fst_path(&common_importable_data.path);
|
||||||
// Add the items from this `ModPath` group. Those are all subsequent items in
|
// Add the items from this `ModPath` group. Those are all subsequent items in
|
||||||
// `importables` whose paths match `path`.
|
// `importables` whose paths match `path`.
|
||||||
let iter = importables
|
let iter = importables
|
||||||
|
@ -387,7 +396,7 @@ pub fn search_dependencies<'a>(
|
||||||
})
|
})
|
||||||
.filter(|item| {
|
.filter(|item| {
|
||||||
!query.case_sensitive // we've already checked the common importables path case-insensitively
|
!query.case_sensitive // we've already checked the common importables path case-insensitively
|
||||||
|| contains_query(&query, &import_map.map[item].path, false)
|
|| import_matches_query(&import_map.map[item], &query, false)
|
||||||
});
|
});
|
||||||
res.extend(iter);
|
res.extend(iter);
|
||||||
|
|
||||||
|
@ -398,19 +407,6 @@ pub fn search_dependencies<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all exported associated items whose names match the query (exactly).
|
|
||||||
for map in &import_maps {
|
|
||||||
if let Some(v) = map.assoc_map.get(&*query.query) {
|
|
||||||
res.extend(v.iter().map(|&assoc| {
|
|
||||||
ItemInNs::Types(match assoc {
|
|
||||||
AssocItemId::FunctionId(it) => it.into(),
|
|
||||||
AssocItemId::ConstId(it) => it.into(),
|
|
||||||
AssocItemId::TypeAliasId(it) => it.into(),
|
|
||||||
})
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,7 +751,7 @@ mod tests {
|
||||||
//- /dep.rs crate:dep
|
//- /dep.rs crate:dep
|
||||||
pub mod fmt {
|
pub mod fmt {
|
||||||
pub trait Display {
|
pub trait Display {
|
||||||
fn fmttt();
|
fn format();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
@ -767,7 +763,7 @@ mod tests {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
dep::fmt (t)
|
dep::fmt (t)
|
||||||
dep::fmt::Display (t)
|
dep::fmt::Display (t)
|
||||||
dep::fmt::Display::fmttt (f)
|
dep::fmt::Display::format (f)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -808,8 +804,8 @@ mod tests {
|
||||||
dep::Fmt (v)
|
dep::Fmt (v)
|
||||||
dep::Fmt (m)
|
dep::Fmt (m)
|
||||||
dep::fmt::Display (t)
|
dep::fmt::Display (t)
|
||||||
dep::format (f)
|
|
||||||
dep::fmt::Display::fmt (f)
|
dep::fmt::Display::fmt (f)
|
||||||
|
dep::format (f)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue