about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-09-24 15:22:57 +0000
committerbors <bors@rust-lang.org>2024-09-24 15:22:57 +0000
commit316a15c9c49c64b253dda681957ea78fff09b295 (patch)
tree27afa9381b115c575b30a6d296fbd262ea10c0df
parentceb495a4d01d2e72e6c4e751ae89387fc45f2223 (diff)
parent8ca54f24e0fda5beaec369cc187c174eee1789eb (diff)
downloadrust-316a15c9c49c64b253dda681957ea78fff09b295.tar.gz
rust-316a15c9c49c64b253dda681957ea78fff09b295.zip
Auto merge of #18164 - ShoyuVanilla:use-as-alias, r=Veykril
fix: Temporary fix for `remove_unused_imports` not handling import aliases correctly

Fixes #18129
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs87
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs23
2 files changed, 97 insertions, 13 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index d4fdc072fb5..c6f99d68748 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -6,7 +6,10 @@ use ide_db::{
     search::{FileReference, ReferenceCategory, SearchScope},
     FxHashMap, RootDatabase,
 };
-use syntax::{ast, AstNode};
+use syntax::{
+    ast::{self, Rename},
+    AstNode,
+};
 use text_edit::TextRange;
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -100,19 +103,19 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
                         hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)),
                         _ => None,
                     })
-                    .any(|d| used_once_in_scope(ctx, d, scope))
+                    .any(|d| used_once_in_scope(ctx, d, u.rename(), scope))
                 {
                     return Some(u);
                 }
             } else if let Definition::Trait(ref t) = def {
                 // If the trait or any item is used.
-                if !std::iter::once(def)
-                    .chain(t.items(ctx.db()).into_iter().map(Definition::from))
-                    .any(|d| used_once_in_scope(ctx, d, scope))
+                if !std::iter::once((def, u.rename()))
+                    .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
+                    .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
                 {
                     return Some(u);
                 }
-            } else if !used_once_in_scope(ctx, def, scope) {
+            } else if !used_once_in_scope(ctx, def, u.rename(), scope) {
                 return Some(u);
             }
 
@@ -138,7 +141,12 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
     }
 }
 
-fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec<SearchScope>) -> bool {
+fn used_once_in_scope(
+    ctx: &AssistContext<'_>,
+    def: Definition,
+    rename: Option<Rename>,
+    scopes: &Vec<SearchScope>,
+) -> bool {
     let mut found = false;
 
     for scope in scopes {
@@ -151,7 +159,10 @@ fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec<Sea
                 false
             }
         };
-        def.usages(&ctx.sema).in_scope(scope).search(&mut search_non_import);
+        def.usages(&ctx.sema)
+            .in_scope(scope)
+            .with_rename(rename.as_ref())
+            .search(&mut search_non_import);
         if found {
             break;
         }
@@ -330,7 +341,7 @@ fn w() {
     }
 
     #[test]
-    fn ranamed_trait_item_use_is_use() {
+    fn renamed_trait_item_use_is_use() {
         check_assist_not_applicable(
             remove_unused_imports,
             r#"
@@ -356,7 +367,7 @@ fn w() {
     }
 
     #[test]
-    fn ranamed_underscore_trait_item_use_is_use() {
+    fn renamed_underscore_trait_item_use_is_use() {
         check_assist_not_applicable(
             remove_unused_imports,
             r#"
@@ -945,4 +956,60 @@ mod z {
 "#,
         );
     }
+
+    #[test]
+    fn use_as_alias() {
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+mod foo {
+    pub struct Foo {}
+}
+
+use foo::Foo as Bar$0;
+
+fn test(_: Bar) {}
+"#,
+        );
+
+        check_assist(
+            remove_unused_imports,
+            r#"
+mod foo {
+    pub struct Foo {}
+    pub struct Bar {}
+    pub struct Qux {}
+    pub trait Quux {
+        fn quxx(&self) {}
+    }
+    impl<T> Quxx for T {}
+}
+
+use foo::{Foo as Bar, Bar as Baz, Qux as _, Quxx as _}$0;
+
+fn test(_: Bar) {
+    let a = ();
+    a.quxx();
+}
+"#,
+            r#"
+mod foo {
+    pub struct Foo {}
+    pub struct Bar {}
+    pub struct Qux {}
+    pub trait Quux {
+        fn quxx(&self) {}
+    }
+    impl<T> Quxx for T {}
+}
+
+use foo::{Foo as Bar, Quxx as _};
+
+fn test(_: Bar) {
+    let a = ();
+    a.quxx();
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index ad30c624c41..4166b08339b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -19,7 +19,7 @@ use parser::SyntaxKind;
 use rustc_hash::{FxHashMap, FxHashSet};
 use span::EditionedFileId;
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, HasName, Rename},
     match_ast, AstNode, AstToken, SmolStr, SyntaxElement, SyntaxNode, TextRange, TextSize,
     ToSmolStr,
 };
@@ -405,6 +405,7 @@ impl Definition {
     pub fn usages<'a>(self, sema: &'a Semantics<'_, RootDatabase>) -> FindUsages<'a> {
         FindUsages {
             def: self,
+            rename: None,
             assoc_item_container: self.as_assoc_item(sema.db).map(|a| a.container(sema.db)),
             sema,
             scope: None,
@@ -417,6 +418,7 @@ impl Definition {
 #[derive(Clone)]
 pub struct FindUsages<'a> {
     def: Definition,
+    rename: Option<&'a Rename>,
     sema: &'a Semantics<'a, RootDatabase>,
     scope: Option<&'a SearchScope>,
     /// The container of our definition should it be an assoc item
@@ -447,6 +449,14 @@ impl<'a> FindUsages<'a> {
         self
     }
 
+    // FIXME: This is just a temporary fix for not handling import aliases like
+    // `use Foo as Bar`. We need to support them in a proper way.
+    // See issue #14079
+    pub fn with_rename(mut self, rename: Option<&'a Rename>) -> Self {
+        self.rename = rename;
+        self
+    }
+
     pub fn at_least_one(&self) -> bool {
         let mut found = false;
         self.search(&mut |_, _| {
@@ -884,9 +894,16 @@ impl<'a> FindUsages<'a> {
             }
         };
 
-        let name = match self.def {
+        let name = match (self.rename, self.def) {
+            (Some(rename), _) => {
+                if rename.underscore_token().is_some() {
+                    None
+                } else {
+                    rename.name().map(|n| n.to_smolstr())
+                }
+            }
             // special case crate modules as these do not have a proper name
-            Definition::Module(module) if module.is_crate_root() => {
+            (_, Definition::Module(module)) if module.is_crate_root() => {
                 // FIXME: This assumes the crate name is always equal to its display name when it
                 // really isn't
                 // we should instead look at the dependency edge name and recursively search our way