mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Auto merge of #16099 - Veykril:flyimport, r=Veykril
internal: Improve import asset perf a bit And bump the query limit from 40 to 100
This commit is contained in:
commit
d4accf8e96
11 changed files with 197 additions and 192 deletions
|
@ -23,6 +23,7 @@ pub struct FileSymbol {
|
|||
pub loc: DeclarationLocation,
|
||||
pub container_name: Option<SmolStr>,
|
||||
pub is_alias: bool,
|
||||
pub is_assoc: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -121,34 +122,34 @@ impl<'a> SymbolCollector<'a> {
|
|||
match module_def_id {
|
||||
ModuleDefId::ModuleId(id) => self.push_module(id),
|
||||
ModuleDefId::FunctionId(id) => {
|
||||
self.push_decl(id);
|
||||
self.push_decl(id, false);
|
||||
self.collect_from_body(id);
|
||||
}
|
||||
ModuleDefId::AdtId(AdtId::StructId(id)) => self.push_decl(id),
|
||||
ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id),
|
||||
ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id),
|
||||
ModuleDefId::AdtId(AdtId::StructId(id)) => self.push_decl(id, false),
|
||||
ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id, false),
|
||||
ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id, false),
|
||||
ModuleDefId::ConstId(id) => {
|
||||
self.push_decl(id);
|
||||
self.push_decl(id, false);
|
||||
self.collect_from_body(id);
|
||||
}
|
||||
ModuleDefId::StaticId(id) => {
|
||||
self.push_decl(id);
|
||||
self.push_decl(id, false);
|
||||
self.collect_from_body(id);
|
||||
}
|
||||
ModuleDefId::TraitId(id) => {
|
||||
self.push_decl(id);
|
||||
self.push_decl(id, false);
|
||||
self.collect_from_trait(id);
|
||||
}
|
||||
ModuleDefId::TraitAliasId(id) => {
|
||||
self.push_decl(id);
|
||||
self.push_decl(id, false);
|
||||
}
|
||||
ModuleDefId::TypeAliasId(id) => {
|
||||
self.push_decl(id);
|
||||
self.push_decl(id, false);
|
||||
}
|
||||
ModuleDefId::MacroId(id) => match id {
|
||||
MacroId::Macro2Id(id) => self.push_decl(id),
|
||||
MacroId::MacroRulesId(id) => self.push_decl(id),
|
||||
MacroId::ProcMacroId(id) => self.push_decl(id),
|
||||
MacroId::Macro2Id(id) => self.push_decl(id, false),
|
||||
MacroId::MacroRulesId(id) => self.push_decl(id, false),
|
||||
MacroId::ProcMacroId(id) => self.push_decl(id, false),
|
||||
},
|
||||
// Don't index these.
|
||||
ModuleDefId::BuiltinType(_) => {}
|
||||
|
@ -190,6 +191,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
container_name: self.current_container_name.clone(),
|
||||
loc: dec_loc,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -202,9 +204,9 @@ impl<'a> SymbolCollector<'a> {
|
|||
for &id in id {
|
||||
if id.module(self.db.upcast()) == module_id {
|
||||
match id {
|
||||
MacroId::Macro2Id(id) => self.push_decl(id),
|
||||
MacroId::MacroRulesId(id) => self.push_decl(id),
|
||||
MacroId::ProcMacroId(id) => self.push_decl(id),
|
||||
MacroId::Macro2Id(id) => self.push_decl(id, false),
|
||||
MacroId::MacroRulesId(id) => self.push_decl(id, false),
|
||||
MacroId::ProcMacroId(id) => self.push_decl(id, false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -266,13 +268,13 @@ impl<'a> SymbolCollector<'a> {
|
|||
|
||||
fn push_assoc_item(&mut self, assoc_item_id: AssocItemId) {
|
||||
match assoc_item_id {
|
||||
AssocItemId::FunctionId(id) => self.push_decl(id),
|
||||
AssocItemId::ConstId(id) => self.push_decl(id),
|
||||
AssocItemId::TypeAliasId(id) => self.push_decl(id),
|
||||
AssocItemId::FunctionId(id) => self.push_decl(id, true),
|
||||
AssocItemId::ConstId(id) => self.push_decl(id, true),
|
||||
AssocItemId::TypeAliasId(id) => self.push_decl(id, true),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_decl<L>(&mut self, id: L)
|
||||
fn push_decl<L>(&mut self, id: L, is_assoc: bool)
|
||||
where
|
||||
L: Lookup + Into<ModuleDefId>,
|
||||
<L as Lookup>::Data: HasSource,
|
||||
|
@ -296,6 +298,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
loc: dec_loc.clone(),
|
||||
container_name: self.current_container_name.clone(),
|
||||
is_alias: true,
|
||||
is_assoc,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -306,6 +309,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
container_name: self.current_container_name.clone(),
|
||||
loc: dec_loc,
|
||||
is_alias: false,
|
||||
is_assoc,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -331,6 +335,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
loc: dec_loc.clone(),
|
||||
container_name: self.current_container_name.clone(),
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -341,6 +346,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
container_name: self.current_container_name.clone(),
|
||||
loc: dec_loc,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -458,13 +458,11 @@ impl Builder {
|
|||
}
|
||||
if let [import_edit] = &*self.imports_to_add {
|
||||
// snippets can have multiple imports, but normal completions only have up to one
|
||||
if let Some(original_path) = import_edit.original_path.as_ref() {
|
||||
label_detail.replace(SmolStr::from(format!(
|
||||
"{} (use {})",
|
||||
label_detail.as_deref().unwrap_or_default(),
|
||||
original_path.display(db)
|
||||
)));
|
||||
}
|
||||
label_detail.replace(SmolStr::from(format!(
|
||||
"{} (use {})",
|
||||
label_detail.as_deref().unwrap_or_default(),
|
||||
import_edit.import_path.display(db)
|
||||
)));
|
||||
} else if let Some(trait_name) = self.trait_name {
|
||||
label_detail.replace(SmolStr::from(format!(
|
||||
"{} (as {trait_name})",
|
||||
|
|
|
@ -181,7 +181,7 @@ fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option<V
|
|||
ctx.config.prefer_no_std,
|
||||
ctx.config.prefer_prelude,
|
||||
)?;
|
||||
Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item, None)))
|
||||
Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item)))
|
||||
};
|
||||
let mut res = Vec::with_capacity(requires.len());
|
||||
for import in requires {
|
||||
|
|
|
@ -597,8 +597,8 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
|
||||
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
|
||||
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -717,7 +717,7 @@ fn main() {
|
|||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
st Item (use foo::bar::baz::Item) Item
|
||||
st Item (use foo::bar) Item
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
@ -725,19 +725,19 @@ fn main() {
|
|||
"Item",
|
||||
fixture,
|
||||
r#"
|
||||
use foo::bar;
|
||||
use foo::bar;
|
||||
|
||||
mod foo {
|
||||
pub mod bar {
|
||||
pub mod baz {
|
||||
pub struct Item;
|
||||
}
|
||||
}
|
||||
mod foo {
|
||||
pub mod bar {
|
||||
pub mod baz {
|
||||
pub struct Item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
bar::baz::Item
|
||||
}"#,
|
||||
fn main() {
|
||||
bar::baz::Item
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -803,7 +803,7 @@ fn main() {
|
|||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
ct TEST_ASSOC (use foo::bar::Item) usize
|
||||
ct TEST_ASSOC (use foo::bar) usize
|
||||
"#]],
|
||||
);
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
//! Look up accessible paths for items.
|
||||
|
||||
use hir::{
|
||||
AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, ModPath, Module, ModuleDef,
|
||||
AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, ModPath, Module, ModuleDef, Name,
|
||||
PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashSet;
|
||||
use itertools::{EitherOrBoth, Itertools};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use syntax::{
|
||||
ast::{self, make, HasName},
|
||||
utils::path_to_string_stripping_turbo_fish,
|
||||
AstNode, SyntaxNode,
|
||||
AstNode, SmolStr, SyntaxNode,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -51,18 +51,11 @@ pub struct TraitImportCandidate {
|
|||
#[derive(Debug)]
|
||||
pub struct PathImportCandidate {
|
||||
/// Optional qualifier before name.
|
||||
pub qualifier: Option<FirstSegmentUnresolved>,
|
||||
pub qualifier: Option<Vec<SmolStr>>,
|
||||
/// The name the item (struct, trait, enum, etc.) should have.
|
||||
pub name: NameToImport,
|
||||
}
|
||||
|
||||
/// A qualifier that has a first segment and it's unresolved.
|
||||
#[derive(Debug)]
|
||||
pub struct FirstSegmentUnresolved {
|
||||
fist_segment: ast::NameRef,
|
||||
full_qualifier: ast::Path,
|
||||
}
|
||||
|
||||
/// A name that will be used during item lookups.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum NameToImport {
|
||||
|
@ -195,18 +188,11 @@ pub struct LocatedImport {
|
|||
/// the original item is the associated constant, but the import has to be a trait that
|
||||
/// defines this constant.
|
||||
pub original_item: ItemInNs,
|
||||
/// A path of the original item.
|
||||
pub original_path: Option<ModPath>,
|
||||
}
|
||||
|
||||
impl LocatedImport {
|
||||
pub fn new(
|
||||
import_path: ModPath,
|
||||
item_to_import: ItemInNs,
|
||||
original_item: ItemInNs,
|
||||
original_path: Option<ModPath>,
|
||||
) -> Self {
|
||||
Self { import_path, item_to_import, original_item, original_path }
|
||||
pub fn new(import_path: ModPath, item_to_import: ItemInNs, original_item: ItemInNs) -> Self {
|
||||
Self { import_path, item_to_import, original_item }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,64 +337,75 @@ fn path_applicable_imports(
|
|||
)
|
||||
.filter_map(|item| {
|
||||
let mod_path = mod_path(item)?;
|
||||
Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path)))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
Some(first_segment_unresolved) => {
|
||||
let unresolved_qualifier =
|
||||
path_to_string_stripping_turbo_fish(&first_segment_unresolved.full_qualifier);
|
||||
let unresolved_first_segment = first_segment_unresolved.fist_segment.text();
|
||||
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,
|
||||
&unresolved_first_segment,
|
||||
&unresolved_qualifier,
|
||||
item,
|
||||
)
|
||||
Some(LocatedImport::new(mod_path, item, item))
|
||||
})
|
||||
.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))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn import_for_item(
|
||||
db: &RootDatabase,
|
||||
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
|
||||
unresolved_first_segment: &str,
|
||||
unresolved_qualifier: &str,
|
||||
unresolved_qualifier: &[SmolStr],
|
||||
original_item: ItemInNs,
|
||||
) -> Option<LocatedImport> {
|
||||
let _p = profile::span("import_assets::import_for_item");
|
||||
let [first_segment, ..] = unresolved_qualifier else { return None };
|
||||
|
||||
let original_item_candidate = item_for_path_search(db, original_item)?;
|
||||
let import_path_candidate = mod_path(original_item_candidate)?;
|
||||
let import_path_string = import_path_candidate.display(db).to_string();
|
||||
let item_as_assoc = item_as_assoc(db, original_item);
|
||||
|
||||
let expected_import_end = if item_as_assoc(db, original_item).is_some() {
|
||||
unresolved_qualifier.to_string()
|
||||
} else {
|
||||
format!("{unresolved_qualifier}::{}", item_name(db, original_item)?.display(db))
|
||||
let (original_item_candidate, trait_item_to_import) = match item_as_assoc {
|
||||
Some(assoc_item) => match assoc_item.container(db) {
|
||||
AssocItemContainer::Trait(trait_) => {
|
||||
let trait_ = ItemInNs::from(ModuleDef::from(trait_));
|
||||
(trait_, Some(trait_))
|
||||
}
|
||||
AssocItemContainer::Impl(impl_) => {
|
||||
(ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?)), None)
|
||||
}
|
||||
},
|
||||
None => (original_item, None),
|
||||
};
|
||||
if !import_path_string.contains(unresolved_first_segment)
|
||||
|| !import_path_string.ends_with(&expected_import_end)
|
||||
{
|
||||
let import_path_candidate = mod_path(original_item_candidate)?;
|
||||
|
||||
let mut import_path_candidate_segments = import_path_candidate.segments().iter().rev();
|
||||
let predicate = |it: EitherOrBoth<&SmolStr, &Name>| match it {
|
||||
// segments match, check next one
|
||||
EitherOrBoth::Both(a, b) if b.as_str() == Some(&**a) => None,
|
||||
// segments mismatch / qualifier is longer than the path, bail out
|
||||
EitherOrBoth::Both(..) | EitherOrBoth::Left(_) => Some(false),
|
||||
// all segments match and we have exhausted the qualifier, proceed
|
||||
EitherOrBoth::Right(_) => Some(true),
|
||||
};
|
||||
if item_as_assoc.is_none() {
|
||||
let item_name = item_name(db, original_item)?.as_text()?;
|
||||
let last_segment = import_path_candidate_segments.next()?;
|
||||
if last_segment.as_str() != Some(&*item_name) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
let ends_with = unresolved_qualifier
|
||||
.iter()
|
||||
.rev()
|
||||
.zip_longest(import_path_candidate_segments)
|
||||
.find_map(predicate)
|
||||
.unwrap_or(true);
|
||||
if !ends_with {
|
||||
return None;
|
||||
}
|
||||
|
||||
let segment_import =
|
||||
find_import_for_segment(db, original_item_candidate, unresolved_first_segment)?;
|
||||
let trait_item_to_import = item_as_assoc(db, original_item)
|
||||
.and_then(|assoc| assoc.containing_trait(db))
|
||||
.map(|trait_| ItemInNs::from(ModuleDef::from(trait_)));
|
||||
let segment_import = find_import_for_segment(db, original_item_candidate, first_segment)?;
|
||||
|
||||
Some(match (segment_import == original_item_candidate, trait_item_to_import) {
|
||||
(true, Some(_)) => {
|
||||
// FIXME we should be able to import both the trait and the segment,
|
||||
|
@ -416,42 +413,37 @@ fn import_for_item(
|
|||
// especially in case of lazy completion edit resolutions.
|
||||
return None;
|
||||
}
|
||||
(false, Some(trait_to_import)) => LocatedImport::new(
|
||||
mod_path(trait_to_import)?,
|
||||
trait_to_import,
|
||||
original_item,
|
||||
mod_path(original_item),
|
||||
),
|
||||
(true, None) => LocatedImport::new(
|
||||
import_path_candidate,
|
||||
original_item_candidate,
|
||||
original_item,
|
||||
mod_path(original_item),
|
||||
),
|
||||
(false, None) => LocatedImport::new(
|
||||
mod_path(segment_import)?,
|
||||
segment_import,
|
||||
original_item,
|
||||
mod_path(original_item),
|
||||
),
|
||||
(false, Some(trait_to_import)) => {
|
||||
LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, original_item)
|
||||
}
|
||||
(true, None) => {
|
||||
LocatedImport::new(import_path_candidate, original_item_candidate, original_item)
|
||||
}
|
||||
(false, None) => {
|
||||
LocatedImport::new(mod_path(segment_import)?, segment_import, original_item)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> {
|
||||
Some(match item {
|
||||
ItemInNs::Types(_) | ItemInNs::Values(_) => match item_as_assoc(db, item) {
|
||||
Some(assoc_item) => match assoc_item.container(db) {
|
||||
AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)),
|
||||
AssocItemContainer::Impl(impl_) => {
|
||||
ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?))
|
||||
}
|
||||
},
|
||||
Some(assoc_item) => item_for_path_search_assoc(db, assoc_item)?,
|
||||
None => item,
|
||||
},
|
||||
ItemInNs::Macros(_) => item,
|
||||
})
|
||||
}
|
||||
|
||||
fn item_for_path_search_assoc(db: &RootDatabase, assoc_item: AssocItem) -> Option<ItemInNs> {
|
||||
Some(match assoc_item.container(db) {
|
||||
AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)),
|
||||
AssocItemContainer::Impl(impl_) => {
|
||||
ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn find_import_for_segment(
|
||||
db: &RootDatabase,
|
||||
original_item: ItemInNs,
|
||||
|
@ -528,6 +520,7 @@ fn trait_applicable_items(
|
|||
.collect();
|
||||
|
||||
let mut located_imports = FxHashSet::default();
|
||||
let mut trait_import_paths = FxHashMap::default();
|
||||
|
||||
if trait_assoc_item {
|
||||
trait_candidate.receiver_ty.iterate_path_candidates(
|
||||
|
@ -545,12 +538,14 @@ fn trait_applicable_items(
|
|||
}
|
||||
let located_trait = assoc.containing_trait(db)?;
|
||||
let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
|
||||
let original_item = assoc_to_item(assoc);
|
||||
let import_path = trait_import_paths
|
||||
.entry(trait_item)
|
||||
.or_insert_with(|| mod_path(trait_item))
|
||||
.clone()?;
|
||||
located_imports.insert(LocatedImport::new(
|
||||
mod_path(trait_item)?,
|
||||
import_path,
|
||||
trait_item,
|
||||
original_item,
|
||||
mod_path(original_item),
|
||||
assoc_to_item(assoc),
|
||||
));
|
||||
}
|
||||
None::<()>
|
||||
|
@ -568,12 +563,14 @@ fn trait_applicable_items(
|
|||
if required_assoc_items.contains(&assoc) {
|
||||
let located_trait = assoc.containing_trait(db)?;
|
||||
let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
|
||||
let original_item = assoc_to_item(assoc);
|
||||
let import_path = trait_import_paths
|
||||
.entry(trait_item)
|
||||
.or_insert_with(|| mod_path(trait_item))
|
||||
.clone()?;
|
||||
located_imports.insert(LocatedImport::new(
|
||||
mod_path(trait_item)?,
|
||||
import_path,
|
||||
trait_item,
|
||||
original_item,
|
||||
mod_path(original_item),
|
||||
assoc_to_item(assoc),
|
||||
));
|
||||
}
|
||||
None::<()>
|
||||
|
@ -671,18 +668,13 @@ fn path_import_candidate(
|
|||
Some(match qualifier {
|
||||
Some(qualifier) => match sema.resolve_path(&qualifier) {
|
||||
None => {
|
||||
let qualifier_start =
|
||||
qualifier.syntax().descendants().find_map(ast::NameRef::cast)?;
|
||||
let qualifier_start_path =
|
||||
qualifier_start.syntax().ancestors().find_map(ast::Path::cast)?;
|
||||
if sema.resolve_path(&qualifier_start_path).is_none() {
|
||||
ImportCandidate::Path(PathImportCandidate {
|
||||
qualifier: Some(FirstSegmentUnresolved {
|
||||
fist_segment: qualifier_start,
|
||||
full_qualifier: qualifier,
|
||||
}),
|
||||
name,
|
||||
})
|
||||
if qualifier.first_qualifier().map_or(true, |it| sema.resolve_path(&it).is_none()) {
|
||||
let mut qualifier = qualifier
|
||||
.segments_of_this_path_only_rev()
|
||||
.map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
qualifier.reverse();
|
||||
ImportCandidate::Path(PathImportCandidate { qualifier: Some(qualifier), name })
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
//! The main reason for this module to exist is the fact that project's items and dependencies' items
|
||||
//! are located in different caches, with different APIs.
|
||||
use either::Either;
|
||||
use hir::{import_map, AsAssocItem, Crate, ItemInNs, Semantics};
|
||||
use hir::{import_map, Crate, ItemInNs, Semantics};
|
||||
use limit::Limit;
|
||||
|
||||
use crate::{imports::import_assets::NameToImport, symbol_index, RootDatabase};
|
||||
|
||||
/// A value to use, when uncertain which limit to pick.
|
||||
pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(40);
|
||||
pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(100);
|
||||
|
||||
pub use import_map::AssocSearchMode;
|
||||
|
||||
|
@ -101,8 +101,8 @@ fn find_items<'a>(
|
|||
.into_iter()
|
||||
.filter(move |candidate| match assoc_item_search {
|
||||
AssocSearchMode::Include => true,
|
||||
AssocSearchMode::Exclude => candidate.def.as_assoc_item(db).is_none(),
|
||||
AssocSearchMode::AssocItemsOnly => candidate.def.as_assoc_item(db).is_some(),
|
||||
AssocSearchMode::Exclude => !candidate.is_assoc,
|
||||
AssocSearchMode::AssocItemsOnly => candidate.is_assoc,
|
||||
})
|
||||
.map(|local_candidate| match local_candidate.def {
|
||||
hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
|
||||
|
|
|
@ -50,7 +50,7 @@ enum SearchMode {
|
|||
Prefix,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Query {
|
||||
query: String,
|
||||
lowercased: String,
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "Struct",
|
||||
|
@ -65,6 +66,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "mul1",
|
||||
|
@ -94,6 +96,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "mul2",
|
||||
|
@ -123,6 +126,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "s1",
|
||||
|
@ -152,6 +156,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "s1",
|
||||
|
@ -181,6 +186,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "s2",
|
||||
|
@ -210,6 +216,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
},
|
||||
],
|
||||
),
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "CONST",
|
||||
|
@ -61,6 +62,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "CONST_WITH_INNER",
|
||||
|
@ -88,6 +90,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "Enum",
|
||||
|
@ -117,6 +120,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "ItemLikeMacro",
|
||||
|
@ -146,6 +150,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "Macro",
|
||||
|
@ -175,6 +180,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "STATIC",
|
||||
|
@ -202,6 +208,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "Struct",
|
||||
|
@ -231,6 +238,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "StructFromMacro",
|
||||
|
@ -260,6 +268,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "StructInFn",
|
||||
|
@ -291,6 +300,7 @@
|
|||
"main",
|
||||
),
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "StructInNamedConst",
|
||||
|
@ -322,6 +332,7 @@
|
|||
"CONST_WITH_INNER",
|
||||
),
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "StructInUnnamedConst",
|
||||
|
@ -351,6 +362,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "Trait",
|
||||
|
@ -378,6 +390,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "Trait",
|
||||
|
@ -407,6 +420,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "Union",
|
||||
|
@ -436,6 +450,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "a_mod",
|
||||
|
@ -465,6 +480,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "b_mod",
|
||||
|
@ -494,6 +510,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "define_struct",
|
||||
|
@ -523,6 +540,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "impl_fn",
|
||||
|
@ -550,6 +568,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: true,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "macro_rules_macro",
|
||||
|
@ -579,6 +598,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "main",
|
||||
|
@ -606,6 +626,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "really_define_struct",
|
||||
|
@ -635,6 +656,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "trait_fn",
|
||||
|
@ -664,6 +686,7 @@
|
|||
"Trait",
|
||||
),
|
||||
is_alias: false,
|
||||
is_assoc: true,
|
||||
},
|
||||
],
|
||||
),
|
||||
|
@ -704,6 +727,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
],
|
||||
),
|
||||
|
@ -744,6 +768,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "StructInModB",
|
||||
|
@ -773,6 +798,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "SuperItemLikeMacro",
|
||||
|
@ -802,6 +828,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "ThisStruct",
|
||||
|
@ -831,6 +858,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "ThisStruct",
|
||||
|
@ -860,6 +888,7 @@
|
|||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
},
|
||||
],
|
||||
),
|
||||
|
|
|
@ -275,10 +275,19 @@ impl ast::Path {
|
|||
successors(Some(self.clone()), ast::Path::qualifier).last().unwrap()
|
||||
}
|
||||
|
||||
pub fn first_qualifier(&self) -> Option<ast::Path> {
|
||||
successors(self.qualifier(), ast::Path::qualifier).last()
|
||||
}
|
||||
|
||||
pub fn first_segment(&self) -> Option<ast::PathSegment> {
|
||||
self.first_qualifier_or_self().segment()
|
||||
}
|
||||
|
||||
// FIXME: Check usages of Self::segments, they might be wrong because of the logic of the bloew function
|
||||
pub fn segments_of_this_path_only_rev(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
|
||||
self.qualifiers_and_self().filter_map(|it| it.segment())
|
||||
}
|
||||
|
||||
pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
|
||||
successors(self.first_segment(), |p| {
|
||||
p.parent_path().parent_path().and_then(|p| p.segment())
|
||||
|
@ -289,6 +298,10 @@ impl ast::Path {
|
|||
successors(self.qualifier(), |p| p.qualifier())
|
||||
}
|
||||
|
||||
pub fn qualifiers_and_self(&self) -> impl Iterator<Item = ast::Path> + Clone {
|
||||
successors(Some(self.clone()), |p| p.qualifier())
|
||||
}
|
||||
|
||||
pub fn top_path(&self) -> ast::Path {
|
||||
let mut this = self.clone();
|
||||
while let Some(path) = this.parent_path() {
|
||||
|
|
|
@ -1,48 +1,8 @@
|
|||
//! A set of utils methods to reuse on other abstraction levels
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{ast, match_ast, AstNode, SyntaxKind};
|
||||
|
||||
pub fn path_to_string_stripping_turbo_fish(path: &ast::Path) -> String {
|
||||
path.syntax()
|
||||
.children()
|
||||
.filter_map(|node| {
|
||||
match_ast! {
|
||||
match node {
|
||||
ast::PathSegment(it) => {
|
||||
Some(it.name_ref()?.to_string())
|
||||
},
|
||||
ast::Path(it) => {
|
||||
Some(path_to_string_stripping_turbo_fish(&it))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
})
|
||||
.join("::")
|
||||
}
|
||||
use crate::SyntaxKind;
|
||||
|
||||
pub fn is_raw_identifier(name: &str) -> bool {
|
||||
let is_keyword = SyntaxKind::from_keyword(name).is_some();
|
||||
is_keyword && !matches!(name, "self" | "crate" | "super" | "Self")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::path_to_string_stripping_turbo_fish;
|
||||
use crate::ast::make;
|
||||
|
||||
#[test]
|
||||
fn turbofishes_are_stripped() {
|
||||
assert_eq!("Vec", path_to_string_stripping_turbo_fish(&make::path_from_text("Vec::<i32>")),);
|
||||
assert_eq!(
|
||||
"Vec::new",
|
||||
path_to_string_stripping_turbo_fish(&make::path_from_text("Vec::<i32>::new")),
|
||||
);
|
||||
assert_eq!(
|
||||
"Vec::new",
|
||||
path_to_string_stripping_turbo_fish(&make::path_from_text("Vec::new()")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue