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 d4fdc072fb5b5..c6f99d68748dd 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) -> bool { +fn used_once_in_scope( + ctx: &AssistContext<'_>, + def: Definition, + rename: Option, + scopes: &Vec, +) -> bool { let mut found = false; for scope in scopes { @@ -151,7 +159,10 @@ fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec 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 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 ad30c624c417e..4166b08339bff 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