|  | 
|  | 1 | +use clippy_utils::diagnostics::span_lint_and_note; | 
|  | 2 | +use clippy_utils::ty::is_copy; | 
|  | 3 | +use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; | 
|  | 4 | +use rustc_lint::{LateContext, LateLintPass}; | 
|  | 5 | +use rustc_session::declare_lint_pass; | 
|  | 6 | + | 
|  | 7 | +declare_clippy_lint! { | 
|  | 8 | +    /// ### What it does | 
|  | 9 | +    /// Checks for mutable reference on a freshly copied data due to | 
|  | 10 | +    /// the use of a block to return an value implementing `Copy`. | 
|  | 11 | +    /// | 
|  | 12 | +    /// ### Why is this bad? | 
|  | 13 | +    /// Using a block will make a copy of the block result if its type | 
|  | 14 | +    /// implements `Copy`. This might be an indication of a failed attempt | 
|  | 15 | +    /// to borrow the original data instead. | 
|  | 16 | +    /// | 
|  | 17 | +    /// ### Example | 
|  | 18 | +    /// ```no_run | 
|  | 19 | +    /// # fn f(_: &mut [i32]) {} | 
|  | 20 | +    /// let arr = &mut [10, 20, 30]; | 
|  | 21 | +    /// f(&mut { *arr }); | 
|  | 22 | +    /// ``` | 
|  | 23 | +    /// If you intend to modify `arr` in `f`, use instead: | 
|  | 24 | +    /// ```no_run | 
|  | 25 | +    /// # fn f(_: &mut [i32]) {} | 
|  | 26 | +    /// let arr = &mut [10, 20, 30]; | 
|  | 27 | +    /// f(arr); | 
|  | 28 | +    /// ``` | 
|  | 29 | +    #[clippy::version = "1.86.0"] | 
|  | 30 | +    pub COPY_THEN_BORROW_MUT, | 
|  | 31 | +    suspicious, | 
|  | 32 | +    "mutable borrow of a data which was just copied" | 
|  | 33 | +} | 
|  | 34 | + | 
|  | 35 | +declare_lint_pass!(CopyThenBorrowMut => [COPY_THEN_BORROW_MUT]); | 
|  | 36 | + | 
|  | 37 | +impl LateLintPass<'_> for CopyThenBorrowMut { | 
|  | 38 | +    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { | 
|  | 39 | +        if !expr.span.from_expansion() | 
|  | 40 | +            && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, sub_expr) = expr.kind | 
|  | 41 | +            && let ExprKind::Block(block, _) = sub_expr.kind | 
|  | 42 | +            && block.span.eq_ctxt(expr.span) | 
|  | 43 | +            && let Some(block_expr) = block.expr | 
|  | 44 | +            && let block_ty = cx.typeck_results().expr_ty_adjusted(block_expr) | 
|  | 45 | +            && is_copy(cx, block_ty) | 
|  | 46 | +        { | 
|  | 47 | +            span_lint_and_note( | 
|  | 48 | +                cx, | 
|  | 49 | +                COPY_THEN_BORROW_MUT, | 
|  | 50 | +                expr.span, | 
|  | 51 | +                "mutable borrow of a value which was just copied", | 
|  | 52 | +                (!block.targeted_by_break).then_some(block_expr.span), | 
|  | 53 | +                "the return value of the block implements `Copy` and will be copied", | 
|  | 54 | +            ); | 
|  | 55 | +        } | 
|  | 56 | +    } | 
|  | 57 | +} | 
0 commit comments