about summary refs log tree commit diff
path: root/clippy_utils
diff options
context:
space:
mode:
authorhamidreza kalbasi <hamidrezakalbasi@protonmail.com>2021-07-29 16:38:17 +0430
committerhamidreza kalbasi <hamidrezakalbasi@protonmail.com>2021-08-09 02:15:10 +0430
commit6d36d1a835370a01cbee58aba038ea0bd712c82b (patch)
treea24834d33f14fc62ab83300853a8ae9a2519178e /clippy_utils
parentdbb10b87f8e4365298ed33a6ed96bffe66a1951e (diff)
downloadrust-6d36d1a835370a01cbee58aba038ea0bd712c82b.tar.gz
rust-6d36d1a835370a01cbee58aba038ea0bd712c82b.zip
merge XOR_SWAP with MANUAL_SWAP
Diffstat (limited to 'clippy_utils')
-rw-r--r--clippy_utils/src/lib.rs48
1 files changed, 48 insertions, 0 deletions
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 59f878f8b20..e930338270c 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -558,6 +558,54 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
     None
 }
 
+/// This method will return tuple of projection stack and root of the expression,
+/// used in `can_mut_borrow_both`.
+///
+/// For example, if `e` represents the `v[0].a.b[x]`
+/// this method will return a tuple, composed of a `Vec`
+/// containing the `Expr`s for `v[0], v[0].a, v[0].a.b, v[0].a.b[x]`
+/// and a `Expr` for root of them, `v`
+fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'a Expr<'hir>) {
+    let mut result = vec![];
+    let root = loop {
+        match e.kind {
+            ExprKind::Index(ep, _) | ExprKind::Field(ep, _) => {
+                result.push(e);
+                e = ep;
+            },
+            _ => break e,
+        };
+    };
+    result.reverse();
+    (result, root)
+}
+
+/// Checks if two expressions can be mutably borrowed simultaneously
+/// and they aren't dependent on borrowing same thing twice
+pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {
+    let (s1, r1) = projection_stack(e1);
+    let (s2, r2) = projection_stack(e2);
+    if !eq_expr_value(cx, r1, r2) {
+        return true;
+    }
+    for (x1, x2) in s1.iter().zip(s2.iter()) {
+        match (&x1.kind, &x2.kind) {
+            (ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {
+                if i1 != i2 {
+                    return true;
+                }
+            },
+            (ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => {
+                if !eq_expr_value(cx, i1, i2) {
+                    return false;
+                }
+            },
+            _ => return false,
+        }
+    }
+    false
+}
+
 /// Checks if the top level expression can be moved into a closure as is.
 pub fn can_move_expr_to_closure_no_visit(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, jump_targets: &[HirId]) -> bool {
     match expr.kind {