Skip to content

Commit 0de459a

Browse files
committed
New lint: copy_then_borrow_mut
1 parent c3239ba commit 0de459a

11 files changed

+268
-67
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5497,6 +5497,7 @@ Released 2018-09-13
54975497
[`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty
54985498
[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
54995499
[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
5500+
[`copy_then_borrow_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_then_borrow_mut
55005501
[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
55015502
[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
55025503
[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
}

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
113113
crate::copies::IF_SAME_THEN_ELSE_INFO,
114114
crate::copies::SAME_FUNCTIONS_IN_IF_CONDITION_INFO,
115115
crate::copy_iterator::COPY_ITERATOR_INFO,
116+
crate::copy_then_borrow_mut::COPY_THEN_BORROW_MUT_INFO,
116117
crate::crate_in_macro_def::CRATE_IN_MACRO_DEF_INFO,
117118
crate::create_dir::CREATE_DIR_INFO,
118119
crate::dbg_macro::DBG_MACRO_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ mod collection_is_never_read;
103103
mod comparison_chain;
104104
mod copies;
105105
mod copy_iterator;
106+
mod copy_then_borrow_mut;
106107
mod crate_in_macro_def;
107108
mod create_dir;
108109
mod dbg_macro;
@@ -980,5 +981,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
980981
store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf)));
981982
store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf)));
982983
store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
984+
store.register_late_pass(|_| Box::new(copy_then_borrow_mut::CopyThenBorrowMut));
983985
// add lints here, do not remove this comment, it's used in `new_lint`
984986
}

tests/ui-toml/excessive_nesting/excessive_nesting.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
clippy::collapsible_if,
1414
clippy::blocks_in_conditions,
1515
clippy::single_match,
16+
clippy::copy_then_borrow_mut
1617
)]
1718

1819
#[macro_use]

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy