about summary refs log tree commit diff
diff options
context:
space:
mode:
authormi_sawa <mi.sawa.1216+git@gmail.com>2022-02-12 02:24:32 +0900
committermi_sawa <mi.sawa.1216+git@gmail.com>2022-02-12 02:24:32 +0900
commit6daa6d5ffe04475c8e54498dc1ebcdb4a884928c (patch)
tree4187b1a9acb5642c99877590e0c53d6a0b2f9117
parent57b3c4b90f4346b3990c1be387c3b3ca7b78412c (diff)
downloadrust-6daa6d5ffe04475c8e54498dc1ebcdb4a884928c.tar.gz
rust-6daa6d5ffe04475c8e54498dc1ebcdb4a884928c.zip
Optimize redundant_clone
by using a static data structure to track transitive relations.
-rw-r--r--clippy_lints/src/redundant_clone.rs61
1 files changed, 36 insertions, 25 deletions
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index 3e0e32857f1..60cc8fddcb4 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth};
 use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
 use if_chain::if_chain;
-use rustc_data_structures::{fx::FxHashMap, transitive_relation::TransitiveRelation};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{def_id, Body, FnDecl, HirId};
@@ -512,7 +512,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
 /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
 /// possible borrowers of `a`.
 struct PossibleBorrowerVisitor<'a, 'tcx> {
-    possible_borrower: TransitiveRelation<mir::Local>,
+    possible_borrower: TransitiveRelation,
     body: &'a mir::Body<'tcx>,
     cx: &'a LateContext<'tcx>,
     possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
@@ -543,18 +543,10 @@ impl<'a, 'tcx> PossibleBorrowerVisitor<'a, 'tcx> {
                 continue;
             }
 
-            let borrowers = self.possible_borrower.reachable_from(&row);
+            let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
+            borrowers.remove(mir::Local::from_usize(0));
             if !borrowers.is_empty() {
-                let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
-                for &c in borrowers {
-                    if c != mir::Local::from_usize(0) {
-                        bs.insert(c);
-                    }
-                }
-
-                if !bs.is_empty() {
-                    map.insert(row, bs);
-                }
+                map.insert(row, borrowers);
             }
         }
 
@@ -644,7 +636,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
 /// For exampel, `_1 = &mut _2` generate _1: {_2,...}
 /// Known Problems: not sure all borrowed are tracked
 struct PossibleOriginVisitor<'a, 'tcx> {
-    possible_origin: TransitiveRelation<mir::Local>,
+    possible_origin: TransitiveRelation,
     body: &'a mir::Body<'tcx>,
 }
 
@@ -663,18 +655,10 @@ impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
                 continue;
             }
 
-            let borrowers = self.possible_origin.reachable_from(&row);
+            let mut borrowers = self.possible_origin.reachable_from(row, self.body.local_decls.len());
+            borrowers.remove(mir::Local::from_usize(0));
             if !borrowers.is_empty() {
-                let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
-                for &c in borrowers {
-                    if c != mir::Local::from_usize(0) {
-                        bs.insert(c);
-                    }
-                }
-
-                if !bs.is_empty() {
-                    map.insert(row, bs);
-                }
+                map.insert(row, borrowers);
             }
         }
         map
@@ -766,3 +750,30 @@ impl PossibleBorrowerMap<'_, '_> {
         self.maybe_live.contains(local)
     }
 }
+
+#[derive(Default)]
+struct TransitiveRelation {
+    relations: FxHashMap<mir::Local, Vec<mir::Local>>,
+}
+impl TransitiveRelation {
+    fn add(&mut self, a: mir::Local, b: mir::Local) {
+        self.relations.entry(a).or_default().push(b);
+    }
+
+    fn reachable_from(&self, a: mir::Local, domain_size: usize) -> HybridBitSet<mir::Local> {
+        let mut seen = HybridBitSet::new_empty(domain_size);
+        seen.insert(a);
+        let mut stack = vec![a];
+        while let Some(u) = stack.pop() {
+            if let Some(edges) = self.relations.get(&u) {
+                for &v in edges {
+                    if seen.insert(v) {
+                        stack.push(v);
+                    }
+                }
+            }
+        }
+        seen.remove(a);
+        seen
+    }
+}