X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=clippy_utils%2Fsrc%2Fusage.rs;h=098ec175fe2d91fcf530df7b6885c81d64e42fa1;hb=543b638dbe4b559e660c76128eb326533f7ea370;hp=0b1ab6b7ea188407e64ea32271737365e7903ef6;hpb=b62694b08fa4068248bf4656adcde39b86cfd815;p=rust.git diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 0b1ab6b7ea1..098ec175fe2 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -1,21 +1,20 @@ use crate as utils; -use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::intravisit; use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, ExprKind, HirId, Path}; +use rustc_hir::HirIdSet; +use rustc_hir::{Expr, ExprKind, HirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; -use rustc_middle::mir::FakeReadCause; use rustc_middle::hir::map::Map; +use rustc_middle::mir::FakeReadCause; use rustc_middle::ty; -use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; +use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. -pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option> { +pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option { let mut delegate = MutVarsDelegate { - used_mutably: FxHashSet::default(), + used_mutably: HirIdSet::default(), skip: false, }; cx.tcx.infer_ctxt().enter(|infcx| { @@ -35,16 +34,12 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Some(delegate.used_mutably) } -pub fn is_potentially_mutated<'tcx>(variable: &'tcx Path<'_>, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool { - if let Res::Local(id) = variable.res { - mutated_variables(expr, cx).map_or(true, |mutated| mutated.contains(&id)) - } else { - true - } +pub fn is_potentially_mutated<'tcx>(variable: HirId, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool { + mutated_variables(expr, cx).map_or(true, |mutated| mutated.contains(&variable)) } struct MutVarsDelegate { - used_mutably: FxHashSet, + used_mutably: HirIdSet, skip: bool, } @@ -59,7 +54,7 @@ fn update(&mut self, cat: &PlaceWithHirId<'tcx>) { //FIXME: This causes false negatives. We can't get the `NodeId` from //`Categorization::Upvar(_)`. So we search for any `Upvar`s in the //`while`-body, not just the ones in the condition. - self.skip = true + self.skip = true; }, _ => {}, } @@ -67,19 +62,19 @@ fn update(&mut self, cat: &PlaceWithHirId<'tcx>) { } impl<'tcx> Delegate<'tcx> for MutVarsDelegate { - fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ConsumeMode) {} + fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { if let ty::BorrowKind::MutBorrow = bk { - self.update(&cmt) + self.update(cmt); } } fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { - self.update(&cmt) + self.update(cmt); } - fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _:HirId) { } + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {} } pub struct ParamBindingIdCollector { @@ -199,3 +194,50 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { recursive_visitor.visit_expr(expression); recursive_visitor.seen_return_break_continue } + +pub struct UsedAfterExprVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + definition: HirId, + past_expr: bool, + used_after_expr: bool, +} +impl<'a, 'tcx> UsedAfterExprVisitor<'a, 'tcx> { + pub fn is_found(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + utils::path_to_local(expr).map_or(false, |definition| { + let mut visitor = UsedAfterExprVisitor { + cx, + expr, + definition, + past_expr: false, + used_after_expr: false, + }; + utils::get_enclosing_block(cx, definition).map_or(false, |block| { + visitor.visit_block(block); + visitor.used_after_expr + }) + }) + } +} + +impl<'a, 'tcx> intravisit::Visitor<'tcx> for UsedAfterExprVisitor<'a, 'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if self.used_after_expr { + return; + } + + if expr.hir_id == self.expr.hir_id { + self.past_expr = true; + } else if self.past_expr && utils::path_to_local_id(expr, self.definition) { + self.used_after_expr = true; + } else { + intravisit::walk_expr(self, expr); + } + } +}