Skip to content

Commit

Permalink
Optimize redundant_clone
Browse files Browse the repository at this point in the history
by using a static data structure to track transitive relations.
  • Loading branch information
MiSawa committed Feb 11, 2022
1 parent 57b3c4b commit 6daa6d5
Showing 1 changed file with 36 additions and 25 deletions.
61 changes: 36 additions & 25 deletions clippy_lints/src/redundant_clone.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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>>,
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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>,
}

Expand All @@ -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
Expand Down Expand Up @@ -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
}
}

0 comments on commit 6daa6d5

Please sign in to comment.