]> git.lizzy.rs Git - rust.git/blobdiff - clippy_utils/src/usage.rs
Add new lint `if_then_panic`
[rust.git] / clippy_utils / src / usage.rs
index 82e4b300068046c2731dbab59551795fdb6ecb6d..098ec175fe2d91fcf530df7b6885c81d64e42fa1 100644 (file)
@@ -1,10 +1,9 @@
 use crate as utils;
 use rustc_hir as hir;
-use rustc_hir::def::Res;
 use rustc_hir::intravisit;
 use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 use rustc_hir::HirIdSet;
-use rustc_hir::{Expr, ExprKind, HirId, Path};
+use rustc_hir::{Expr, ExprKind, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
@@ -35,12 +34,8 @@ 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 {
@@ -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<Self::Map> {
+        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);
+        }
+    }
+}