Skip to content

Commit 6f3a3bd

Browse files
bors[bot]Veykril
andauthored
Merge #9551
9551: fix: `replace_qualified_name_with_use` keeps qualifier for import r=Veykril a=Veykril Fixes #9537, #9540 bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents 637dbb2 + 0db5992 commit 6f3a3bd

File tree

1 file changed

+57
-9
lines changed

1 file changed

+57
-9
lines changed

crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use ide_db::helpers::{
33
insert_use::{insert_use, ImportScope},
44
mod_path_to_ast,
55
};
6-
use syntax::{ast, match_ast, ted, AstNode, SyntaxNode};
6+
use syntax::{
7+
ast::{self, make},
8+
match_ast, ted, AstNode, SyntaxNode,
9+
};
710

811
use crate::{AssistContext, AssistId, AssistKind, Assists};
912

@@ -38,20 +41,26 @@ pub(crate) fn replace_qualified_name_with_use(
3841
return None;
3942
}
4043

41-
let res = ctx.sema.resolve_path(&path)?;
42-
let def: hir::ItemInNs = match res {
43-
hir::PathResolution::Def(def) if def.as_assoc_item(ctx.sema.db).is_none() => def.into(),
44-
hir::PathResolution::Macro(mac) => mac.into(),
44+
// only offer replacement for non assoc items
45+
match ctx.sema.resolve_path(&path)? {
46+
hir::PathResolution::Def(def) if def.as_assoc_item(ctx.sema.db).is_none() => (),
47+
hir::PathResolution::Macro(_) => (),
48+
_ => return None,
49+
}
50+
// then search for an import for the first path segment of what we want to replace
51+
// that way it is less likely that we import the item from a different location due re-exports
52+
let module = match ctx.sema.resolve_path(&path.first_qualifier_or_self())? {
53+
hir::PathResolution::Def(module @ hir::ModuleDef::Module(_)) => module,
4554
_ => return None,
4655
};
4756

48-
let target = path.syntax().text_range();
4957
let scope = ImportScope::find_insert_use_container_with_macros(path.syntax(), &ctx.sema)?;
50-
let mod_path = ctx.sema.scope(path.syntax()).module()?.find_use_path_prefixed(
58+
let path_to_qualifier = ctx.sema.scope(path.syntax()).module()?.find_use_path_prefixed(
5159
ctx.sema.db,
52-
def,
60+
module,
5361
ctx.config.insert_use.prefix_kind,
5462
)?;
63+
let target = path.syntax().text_range();
5564
acc.add(
5665
AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
5766
"Replace qualified path with use",
@@ -64,7 +73,11 @@ pub(crate) fn replace_qualified_name_with_use(
6473
ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
6574
ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
6675
};
67-
let path = mod_path_to_ast(&mod_path);
76+
// stick the found import in front of the to be replaced path
77+
let path = match mod_path_to_ast(&path_to_qualifier).qualifier() {
78+
Some(qualifier) => make::path_concat(qualifier, path),
79+
None => path,
80+
};
6881
shorten_paths(scope.as_syntax_node(), &path.clone_for_update());
6982
insert_use(&scope, path, &ctx.config.insert_use);
7083
},
@@ -300,6 +313,41 @@ impl Foo {
300313
fn main() {
301314
Foo::foo$0();
302315
}
316+
",
317+
);
318+
}
319+
320+
#[test]
321+
fn replace_reuses_path_qualifier() {
322+
check_assist(
323+
replace_qualified_name_with_use,
324+
r"
325+
pub mod foo {
326+
struct Foo;
327+
}
328+
329+
mod bar {
330+
pub use super::foo::Foo as Bar;
331+
}
332+
333+
fn main() {
334+
foo::Foo$0;
335+
}
336+
",
337+
r"
338+
use foo::Foo;
339+
340+
pub mod foo {
341+
struct Foo;
342+
}
343+
344+
mod bar {
345+
pub use super::foo::Foo as Bar;
346+
}
347+
348+
fn main() {
349+
Foo;
350+
}
303351
",
304352
);
305353
}

0 commit comments

Comments
 (0)