Skip to content

Commit 316a15c

Browse files
committed
Auto merge of rust-lang#18164 - ShoyuVanilla:use-as-alias, r=Veykril
fix: Temporary fix for `remove_unused_imports` not handling import aliases correctly Fixes rust-lang#18129
2 parents ceb495a + 8ca54f2 commit 316a15c

File tree

2 files changed

+97
-13
lines changed

2 files changed

+97
-13
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs

+77-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ use ide_db::{
66
search::{FileReference, ReferenceCategory, SearchScope},
77
FxHashMap, RootDatabase,
88
};
9-
use syntax::{ast, AstNode};
9+
use syntax::{
10+
ast::{self, Rename},
11+
AstNode,
12+
};
1013
use text_edit::TextRange;
1114

1215
use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -100,19 +103,19 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
100103
hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)),
101104
_ => None,
102105
})
103-
.any(|d| used_once_in_scope(ctx, d, scope))
106+
.any(|d| used_once_in_scope(ctx, d, u.rename(), scope))
104107
{
105108
return Some(u);
106109
}
107110
} else if let Definition::Trait(ref t) = def {
108111
// If the trait or any item is used.
109-
if !std::iter::once(def)
110-
.chain(t.items(ctx.db()).into_iter().map(Definition::from))
111-
.any(|d| used_once_in_scope(ctx, d, scope))
112+
if !std::iter::once((def, u.rename()))
113+
.chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
114+
.any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
112115
{
113116
return Some(u);
114117
}
115-
} else if !used_once_in_scope(ctx, def, scope) {
118+
} else if !used_once_in_scope(ctx, def, u.rename(), scope) {
116119
return Some(u);
117120
}
118121

@@ -138,7 +141,12 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
138141
}
139142
}
140143

141-
fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec<SearchScope>) -> bool {
144+
fn used_once_in_scope(
145+
ctx: &AssistContext<'_>,
146+
def: Definition,
147+
rename: Option<Rename>,
148+
scopes: &Vec<SearchScope>,
149+
) -> bool {
142150
let mut found = false;
143151

144152
for scope in scopes {
@@ -151,7 +159,10 @@ fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec<Sea
151159
false
152160
}
153161
};
154-
def.usages(&ctx.sema).in_scope(scope).search(&mut search_non_import);
162+
def.usages(&ctx.sema)
163+
.in_scope(scope)
164+
.with_rename(rename.as_ref())
165+
.search(&mut search_non_import);
155166
if found {
156167
break;
157168
}
@@ -330,7 +341,7 @@ fn w() {
330341
}
331342

332343
#[test]
333-
fn ranamed_trait_item_use_is_use() {
344+
fn renamed_trait_item_use_is_use() {
334345
check_assist_not_applicable(
335346
remove_unused_imports,
336347
r#"
@@ -356,7 +367,7 @@ fn w() {
356367
}
357368

358369
#[test]
359-
fn ranamed_underscore_trait_item_use_is_use() {
370+
fn renamed_underscore_trait_item_use_is_use() {
360371
check_assist_not_applicable(
361372
remove_unused_imports,
362373
r#"
@@ -942,6 +953,62 @@ pub struct X();
942953
mod z {
943954
mod foo;
944955
}
956+
"#,
957+
);
958+
}
959+
960+
#[test]
961+
fn use_as_alias() {
962+
check_assist_not_applicable(
963+
remove_unused_imports,
964+
r#"
965+
mod foo {
966+
pub struct Foo {}
967+
}
968+
969+
use foo::Foo as Bar$0;
970+
971+
fn test(_: Bar) {}
972+
"#,
973+
);
974+
975+
check_assist(
976+
remove_unused_imports,
977+
r#"
978+
mod foo {
979+
pub struct Foo {}
980+
pub struct Bar {}
981+
pub struct Qux {}
982+
pub trait Quux {
983+
fn quxx(&self) {}
984+
}
985+
impl<T> Quxx for T {}
986+
}
987+
988+
use foo::{Foo as Bar, Bar as Baz, Qux as _, Quxx as _}$0;
989+
990+
fn test(_: Bar) {
991+
let a = ();
992+
a.quxx();
993+
}
994+
"#,
995+
r#"
996+
mod foo {
997+
pub struct Foo {}
998+
pub struct Bar {}
999+
pub struct Qux {}
1000+
pub trait Quux {
1001+
fn quxx(&self) {}
1002+
}
1003+
impl<T> Quxx for T {}
1004+
}
1005+
1006+
use foo::{Foo as Bar, Quxx as _};
1007+
1008+
fn test(_: Bar) {
1009+
let a = ();
1010+
a.quxx();
1011+
}
9451012
"#,
9461013
);
9471014
}

src/tools/rust-analyzer/crates/ide-db/src/search.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use parser::SyntaxKind;
1919
use rustc_hash::{FxHashMap, FxHashSet};
2020
use span::EditionedFileId;
2121
use syntax::{
22-
ast::{self, HasName},
22+
ast::{self, HasName, Rename},
2323
match_ast, AstNode, AstToken, SmolStr, SyntaxElement, SyntaxNode, TextRange, TextSize,
2424
ToSmolStr,
2525
};
@@ -405,6 +405,7 @@ impl Definition {
405405
pub fn usages<'a>(self, sema: &'a Semantics<'_, RootDatabase>) -> FindUsages<'a> {
406406
FindUsages {
407407
def: self,
408+
rename: None,
408409
assoc_item_container: self.as_assoc_item(sema.db).map(|a| a.container(sema.db)),
409410
sema,
410411
scope: None,
@@ -417,6 +418,7 @@ impl Definition {
417418
#[derive(Clone)]
418419
pub struct FindUsages<'a> {
419420
def: Definition,
421+
rename: Option<&'a Rename>,
420422
sema: &'a Semantics<'a, RootDatabase>,
421423
scope: Option<&'a SearchScope>,
422424
/// The container of our definition should it be an assoc item
@@ -447,6 +449,14 @@ impl<'a> FindUsages<'a> {
447449
self
448450
}
449451

452+
// FIXME: This is just a temporary fix for not handling import aliases like
453+
// `use Foo as Bar`. We need to support them in a proper way.
454+
// See issue #14079
455+
pub fn with_rename(mut self, rename: Option<&'a Rename>) -> Self {
456+
self.rename = rename;
457+
self
458+
}
459+
450460
pub fn at_least_one(&self) -> bool {
451461
let mut found = false;
452462
self.search(&mut |_, _| {
@@ -884,9 +894,16 @@ impl<'a> FindUsages<'a> {
884894
}
885895
};
886896

887-
let name = match self.def {
897+
let name = match (self.rename, self.def) {
898+
(Some(rename), _) => {
899+
if rename.underscore_token().is_some() {
900+
None
901+
} else {
902+
rename.name().map(|n| n.to_smolstr())
903+
}
904+
}
888905
// special case crate modules as these do not have a proper name
889-
Definition::Module(module) if module.is_crate_root() => {
906+
(_, Definition::Module(module)) if module.is_crate_root() => {
890907
// FIXME: This assumes the crate name is always equal to its display name when it
891908
// really isn't
892909
// we should instead look at the dependency edge name and recursively search our way

0 commit comments

Comments
 (0)