Merge commit '21b06c1beb' into sync-from-ra

This commit is contained in:
Laurențiu Nicola 2023-12-18 09:21:55 +02:00
parent cac74d98f6
commit e37cf75791
59 changed files with 1080 additions and 477 deletions

View file

@ -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;
}

View file

@ -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;
@ -36,7 +36,9 @@ pub fn items_with_name<'a>(
NameToImport::Prefix(exact_name, case_sensitive)
| NameToImport::Exact(exact_name, case_sensitive) => {
let mut local_query = symbol_index::Query::new(exact_name.clone());
let mut external_query = import_map::Query::new(exact_name);
let mut external_query =
// import_map::Query::new(exact_name).assoc_search_mode(assoc_item_search);
import_map::Query::new(exact_name);
if prefix {
local_query.prefix();
external_query = external_query.prefix();
@ -101,8 +103,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),

View file

@ -50,7 +50,7 @@ enum SearchMode {
Prefix,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Query {
query: String,
lowercased: String,

View file

@ -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,
},
],
),

View file

@ -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,
},
],
),