Skip to content

Commit ada5f20

Browse files
committed
fix: Fix path qualified auto-importing completions not working with re-exports
Prior to this commit we used to generate import paths, then zipped them with the existing qualifier to check if they agree on the path to import. This is brittle when re-exports come into play causing items to have multiple applicable paths that refer to them. This commit instead rewrites this logic by generating the import path for the qualifier, verifying that the rest of the qualifier resolves and then doing a final lookup on that resolution result for the final segment instead.
1 parent 65c8d12 commit ada5f20

File tree

9 files changed

+221
-134
lines changed

9 files changed

+221
-134
lines changed

crates/hir/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3105,10 +3105,10 @@ impl From<ModuleDef> for ItemInNs {
31053105
}
31063106

31073107
impl ItemInNs {
3108-
pub fn as_module_def(self) -> Option<ModuleDef> {
3108+
pub fn into_module_def(self) -> ModuleDef {
31093109
match self {
3110-
ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
3111-
ItemInNs::Macros(_) => None,
3110+
ItemInNs::Types(id) | ItemInNs::Values(id) => id,
3111+
ItemInNs::Macros(id) => ModuleDef::Macro(id),
31123112
}
31133113
}
31143114

crates/hir/src/semantics.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ use stdx::TupleExt;
3939
use syntax::{
4040
algo::skip_trivia_token,
4141
ast::{self, HasAttrs as _, HasGenericParams},
42-
AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
43-
TextSize,
42+
AstNode, AstToken, Direction, SmolStr, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken,
43+
TextRange, TextSize,
4444
};
4545
use triomphe::Arc;
4646

@@ -1540,6 +1540,21 @@ impl<'db> SemanticsImpl<'db> {
15401540
Some(items.iter_items().map(|(item, _)| item.into()))
15411541
}
15421542

1543+
pub fn resolve_mod_path_relative(
1544+
&self,
1545+
to: Module,
1546+
segments: impl IntoIterator<Item = SmolStr>,
1547+
) -> Option<impl Iterator<Item = ItemInNs>> {
1548+
let items = to.id.resolver(self.db.upcast()).resolve_module_path_in_items(
1549+
self.db.upcast(),
1550+
&ModPath::from_segments(
1551+
hir_def::path::PathKind::Plain,
1552+
segments.into_iter().map(|it| Name::new(&it, SyntaxContextId::ROOT)),
1553+
),
1554+
);
1555+
Some(items.iter_items().map(|(item, _)| item.into()))
1556+
}
1557+
15431558
fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
15441559
self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit)
15451560
}

crates/ide-assists/src/handlers/qualify_method_call.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fn item_for_path_search(db: &dyn HirDatabase, item: ItemInNs) -> Option<ItemInNs
8686
}
8787

8888
fn item_as_assoc(db: &dyn HirDatabase, item: ItemInNs) -> Option<AssocItem> {
89-
item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db))
89+
item.into_module_def().as_assoc_item(db)
9090
}
9191

9292
#[cfg(test)]

crates/ide-assists/src/handlers/qualify_path.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
5151
let candidate = import_assets.import_candidate();
5252
let qualify_candidate = match syntax_under_caret.clone() {
5353
NodeOrToken::Node(syntax_under_caret) => match candidate {
54-
ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => {
54+
ImportCandidate::Path(candidate) if !candidate.qualifier.is_empty() => {
5555
cov_mark::hit!(qualify_path_qualifier_start);
5656
let path = ast::Path::cast(syntax_under_caret)?;
5757
let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
@@ -219,11 +219,9 @@ fn find_trait_method(
219219
}
220220

221221
fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
222-
let item_module_def = item.as_module_def()?;
223-
224-
match item_module_def {
222+
match item.into_module_def() {
225223
hir::ModuleDef::Trait(trait_) => Some(trait_),
226-
_ => item_module_def.as_assoc_item(db)?.container_trait(db),
224+
item_module_def => item_module_def.as_assoc_item(db)?.container_trait(db),
227225
}
228226
}
229227

@@ -247,7 +245,7 @@ fn label(
247245
let import_path = &import.import_path;
248246

249247
match candidate {
250-
ImportCandidate::Path(candidate) if candidate.qualifier.is_none() => {
248+
ImportCandidate::Path(candidate) if candidate.qualifier.is_empty() => {
251249
format!("Qualify as `{}`", import_path.display(db, edition))
252250
}
253251
_ => format!("Qualify with `{}`", import_path.display(db, edition)),

crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub(crate) fn replace_derive_with_manual_impl(
7878
NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
7979
items_locator::AssocSearchMode::Exclude,
8080
)
81-
.filter_map(|item| match item.as_module_def()? {
81+
.filter_map(|item| match item.into_module_def() {
8282
ModuleDef::Trait(trait_) => Some(trait_),
8383
_ => None,
8484
})

crates/ide-assists/src/handlers/wrap_return_type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ fn wrapper_alias(
198198
);
199199

200200
ctx.sema.resolve_mod_path(ret_type.syntax(), &wrapper_path).and_then(|def| {
201-
def.filter_map(|def| match def.as_module_def()? {
201+
def.filter_map(|def| match def.into_module_def() {
202202
hir::ModuleDef::TypeAlias(alias) => {
203203
let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?;
204204
(&enum_ty == core_wrapper).then_some(alias)

crates/ide-completion/src/tests/flyimport.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,3 +1720,45 @@ fn function() {
17201720
"#]],
17211721
);
17221722
}
1723+
1724+
#[test]
1725+
fn intrinsics() {
1726+
check(
1727+
r#"
1728+
//- /core.rs crate:core
1729+
pub mod intrinsics {
1730+
extern "rust-intrinsic" {
1731+
pub fn transmute<Src, Dst>(src: Src) -> Dst;
1732+
}
1733+
}
1734+
pub mod mem {
1735+
pub use crate::intrinsics::transmute;
1736+
}
1737+
//- /main.rs crate:main deps:core
1738+
fn function() {
1739+
transmute$0
1740+
}
1741+
"#,
1742+
expect![[r#"
1743+
fn transmute(…) (use core::mem::transmute) unsafe fn(Src) -> Dst
1744+
"#]],
1745+
);
1746+
check(
1747+
r#"
1748+
//- /core.rs crate:core
1749+
pub mod intrinsics {
1750+
extern "rust-intrinsic" {
1751+
pub fn transmute<Src, Dst>(src: Src) -> Dst;
1752+
}
1753+
}
1754+
pub mod mem {
1755+
pub use crate::intrinsics::transmute;
1756+
}
1757+
//- /main.rs crate:main deps:core
1758+
fn function() {
1759+
mem::transmute$0
1760+
}
1761+
"#,
1762+
expect![""],
1763+
);
1764+
}

0 commit comments

Comments
 (0)