summary refs log tree commit diff
path: root/compiler/rustc_resolve/src/check_unused.rs
diff options
context:
space:
mode:
authorsurechen <chenshuo17@huawei.com>2023-11-10 10:11:24 +0800
committersurechen <chenshuo17@huawei.com>2024-02-18 16:38:11 +0800
commita61126cef6c4083d57e22835033eb2eefdd31bac (patch)
tree8816d1d780e97b77f943c48de09ee330fee3ac9d /compiler/rustc_resolve/src/check_unused.rs
parentd3df8ff85121146f2ac5e863e0c9eaba4bf35d32 (diff)
downloadrust-a61126cef6c4083d57e22835033eb2eefdd31bac.tar.gz
rust-a61126cef6c4083d57e22835033eb2eefdd31bac.zip
By tracking import use types to check whether it is scope uses or the other situations like module-relative uses, we can do more accurate redundant import checking.
fixes #117448

For example unnecessary imports in std::prelude that can be eliminated:

```rust
use std::option::Option::Some;//~ WARNING the item `Some` is imported redundantly
use std::option::Option::None; //~ WARNING the item `None` is imported redundantly
```
Diffstat (limited to 'compiler/rustc_resolve/src/check_unused.rs')
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs46
1 files changed, 36 insertions, 10 deletions
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index c14788b841d..37cc50f6943 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -27,9 +27,10 @@ use crate::imports::ImportKind;
 use crate::module_to_string;
 use crate::Resolver;
 
+use crate::NameBindingKind;
 use rustc_ast as ast;
 use rustc_ast::visit::{self, Visitor};
-use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{pluralize, MultiSpan};
 use rustc_hir::def::{DefKind, Res};
@@ -38,14 +39,14 @@ use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, DUMMY_SP};
 
-struct UnusedImport<'a> {
-    use_tree: &'a ast::UseTree,
+struct UnusedImport {
+    use_tree: ast::UseTree,
     use_tree_id: ast::NodeId,
     item_span: Span,
     unused: UnordSet<ast::NodeId>,
 }
 
-impl<'a> UnusedImport<'a> {
+impl UnusedImport {
     fn add(&mut self, id: ast::NodeId) {
         self.unused.insert(id);
     }
@@ -54,7 +55,7 @@ impl<'a> UnusedImport<'a> {
 struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     r: &'a mut Resolver<'b, 'tcx>,
     /// All the (so far) unused imports, grouped path list
-    unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>,
+    unused_imports: FxIndexMap<ast::NodeId, UnusedImport>,
     extern_crate_items: Vec<ExternCrateToLint>,
     base_use_tree: Option<&'a ast::UseTree>,
     base_id: ast::NodeId,
@@ -100,9 +101,9 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
         }
     }
 
-    fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport<'a> {
+    fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport {
         let use_tree_id = self.base_id;
-        let use_tree = self.base_use_tree.unwrap();
+        let use_tree = self.base_use_tree.unwrap().clone();
         let item_span = self.item_span;
 
         self.unused_imports.entry(id).or_insert_with(|| UnusedImport {
@@ -197,7 +198,7 @@ enum UnusedSpanResult {
 }
 
 fn calc_unused_spans(
-    unused_import: &UnusedImport<'_>,
+    unused_import: &UnusedImport,
     use_tree: &ast::UseTree,
     use_tree_id: ast::NodeId,
 ) -> UnusedSpanResult {
@@ -287,7 +288,7 @@ impl Resolver<'_, '_> {
 
         for import in self.potentially_unused_imports.iter() {
             match import.kind {
-                _ if import.used.get()
+                _ if import.used.get().is_some()
                     || import.expect_vis().is_public()
                     || import.span.is_dummy() =>
                 {
@@ -336,7 +337,7 @@ impl Resolver<'_, '_> {
 
         for unused in visitor.unused_imports.values() {
             let mut fixes = Vec::new();
-            let spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
+            let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
                 UnusedSpanResult::Used => continue,
                 UnusedSpanResult::FlatUnused(span, remove) => {
                     fixes.push((remove, String::new()));
@@ -483,5 +484,30 @@ impl Resolver<'_, '_> {
                 BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span },
             );
         }
+
+        let unused_imports = visitor.unused_imports;
+        let mut check_redundant_imports = FxIndexSet::default();
+        for module in self.arenas.local_modules().iter() {
+            for (_key, resolution) in self.resolutions(*module).borrow().iter() {
+                let resolution = resolution.borrow();
+
+                if let Some(binding) = resolution.binding
+                    && let NameBindingKind::Import { import, .. } = binding.kind
+                    && let ImportKind::Single { id, .. } = import.kind
+                {
+                    if let Some(unused_import) = unused_imports.get(&import.root_id)
+                        && unused_import.unused.contains(&id)
+                    {
+                        continue;
+                    }
+
+                    check_redundant_imports.insert(import);
+                }
+            }
+        }
+
+        for import in check_redundant_imports {
+            self.check_for_redundant_imports(import);
+        }
     }
 }