Skip to content

Commit

Permalink
New lint: copy_then_borrow_mut
Browse files Browse the repository at this point in the history
  • Loading branch information
samueltardieu committed Jan 12, 2025
1 parent 34d109f commit 1ac5de7
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 67 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5497,6 +5497,7 @@ Released 2018-09-13
[`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty
[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
[`copy_then_borrow_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_then_borrow_mut
[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
Expand Down
57 changes: 57 additions & 0 deletions clippy_lints/src/copy_then_borrow_mut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::ty::is_copy;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;

declare_clippy_lint! {
/// ### What it does
/// Checks for mutable reference on a freshly copied data due to
/// the use of a block to return an value implementing `Copy`.
///
/// ### Why is this bad?
/// Using a block will make a copy of the block result if its type
/// implements `Copy`. This might be an indication of a failed attempt
/// to borrow the original data instead.
///
/// ### Example
/// ```no_run
/// # fn f(_: &mut [i32]) {}
/// let arr = &mut [10, 20, 30];
/// f(&mut { *arr });
/// ```
/// If you intend to modify `arr` in `f`, use instead:
/// ```no_run
/// # fn f(_: &mut [i32]) {}
/// let arr = &mut [10, 20, 30];
/// f(arr);
/// ```
#[clippy::version = "1.86.0"]
pub COPY_THEN_BORROW_MUT,
suspicious,
"mutable borrow of a data which was just copied"
}

declare_lint_pass!(CopyThenBorrowMut => [COPY_THEN_BORROW_MUT]);

impl LateLintPass<'_> for CopyThenBorrowMut {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if !expr.span.from_expansion()
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, sub_expr) = expr.kind
&& let ExprKind::Block(block, _) = sub_expr.kind
&& block.span.eq_ctxt(expr.span)
&& let Some(block_expr) = block.expr
&& let block_ty = cx.typeck_results().expr_ty_adjusted(block_expr)
&& is_copy(cx, block_ty)
{
span_lint_and_note(
cx,
COPY_THEN_BORROW_MUT,
expr.span,
"mutable borrow of a value which was just copied",
(!block.targeted_by_break).then_some(block_expr.span),
"the return value of the block implements `Copy` and will be copied",
);
}
}
}
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::copies::IF_SAME_THEN_ELSE_INFO,
crate::copies::SAME_FUNCTIONS_IN_IF_CONDITION_INFO,
crate::copy_iterator::COPY_ITERATOR_INFO,
crate::copy_then_borrow_mut::COPY_THEN_BORROW_MUT_INFO,
crate::crate_in_macro_def::CRATE_IN_MACRO_DEF_INFO,
crate::create_dir::CREATE_DIR_INFO,
crate::dbg_macro::DBG_MACRO_INFO,
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ mod collection_is_never_read;
mod comparison_chain;
mod copies;
mod copy_iterator;
mod copy_then_borrow_mut;
mod crate_in_macro_def;
mod create_dir;
mod dbg_macro;
Expand Down Expand Up @@ -972,5 +973,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
store.register_late_pass(|_| Box::new(copy_then_borrow_mut::CopyThenBorrowMut));
// add lints here, do not remove this comment, it's used in `new_lint`
}
1 change: 1 addition & 0 deletions tests/ui-toml/excessive_nesting/excessive_nesting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
clippy::collapsible_if,
clippy::blocks_in_conditions,
clippy::single_match,
clippy::copy_then_borrow_mut
)]

#[macro_use]
Expand Down
Loading

0 comments on commit 1ac5de7

Please sign in to comment.