Skip to content

Commit 4f4abf4

Browse files
committed
Warn about explicit self-assignment
Warn about assignments where left-hand side place expression is the same as right-hand side value expression. For example, warn about assignment in: ```rust pub struct Event { id: usize, x: i32, y: i32, } pub fn copy_position(a: &mut Event, b: &Event) { a.x = b.x; a.y = a.y; } ```
1 parent d1dbf79 commit 4f4abf4

File tree

6 files changed

+201
-0
lines changed

6 files changed

+201
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1690,6 +1690,7 @@ Released 2018-09-13
16901690
[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
16911691
[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
16921692
[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
1693+
[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
16931694
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
16941695
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
16951696
[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same

clippy_lints/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ mod reference;
284284
mod regex;
285285
mod repeat_once;
286286
mod returns;
287+
mod self_assignment;
287288
mod serde_api;
288289
mod shadow;
289290
mod single_component_path_imports;
@@ -773,6 +774,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
773774
&repeat_once::REPEAT_ONCE,
774775
&returns::LET_AND_RETURN,
775776
&returns::NEEDLESS_RETURN,
777+
&self_assignment::SELF_ASSIGNMENT,
776778
&serde_api::SERDE_API_MISUSE,
777779
&shadow::SHADOW_REUSE,
778780
&shadow::SHADOW_SAME,
@@ -1090,6 +1092,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10901092
store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
10911093
store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
10921094
store.register_late_pass(|| box repeat_once::RepeatOnce);
1095+
store.register_late_pass(|| box self_assignment::SelfAssignment);
10931096

10941097
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
10951098
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1421,6 +1424,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
14211424
LintId::of(&repeat_once::REPEAT_ONCE),
14221425
LintId::of(&returns::LET_AND_RETURN),
14231426
LintId::of(&returns::NEEDLESS_RETURN),
1427+
LintId::of(&self_assignment::SELF_ASSIGNMENT),
14241428
LintId::of(&serde_api::SERDE_API_MISUSE),
14251429
LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
14261430
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
@@ -1714,6 +1718,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
17141718
LintId::of(&ptr::MUT_FROM_REF),
17151719
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
17161720
LintId::of(&regex::INVALID_REGEX),
1721+
LintId::of(&self_assignment::SELF_ASSIGNMENT),
17171722
LintId::of(&serde_api::SERDE_API_MISUSE),
17181723
LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
17191724
LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),

clippy_lints/src/self_assignment.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use crate::utils::{eq_expr_value, snippet, span_lint};
2+
use rustc_hir::{Expr, ExprKind};
3+
use rustc_lint::{LateContext, LateLintPass};
4+
use rustc_session::{declare_lint_pass, declare_tool_lint};
5+
6+
declare_clippy_lint! {
7+
/// **What it does:** Checks for explicit self-assignments.
8+
///
9+
/// **Why is this bad?** Self-assignments are redundant and unlikely to be
10+
/// intentional.
11+
///
12+
/// **Known problems:** If expression contains any deref coercions or
13+
/// indexing operations they are assumed not to have any side effects.
14+
///
15+
/// **Example:**
16+
///
17+
/// ```rust
18+
/// struct Event {
19+
/// id: usize,
20+
/// x: i32,
21+
/// y: i32,
22+
/// }
23+
///
24+
/// fn copy_position(a: &mut Event, b: &Event) {
25+
/// a.x = b.x;
26+
/// a.y = a.y;
27+
/// }
28+
/// ```
29+
pub SELF_ASSIGNMENT,
30+
correctness,
31+
"explicit self-assignment"
32+
}
33+
34+
declare_lint_pass!(SelfAssignment => [SELF_ASSIGNMENT]);
35+
36+
impl<'tcx> LateLintPass<'tcx> for SelfAssignment {
37+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
38+
if let ExprKind::Assign(lhs, rhs, _) = &expr.kind {
39+
if eq_expr_value(cx, lhs, rhs) {
40+
let lhs = snippet(cx, lhs.span, "<lhs>");
41+
let rhs = snippet(cx, rhs.span, "<rhs>");
42+
span_lint(
43+
cx,
44+
SELF_ASSIGNMENT,
45+
expr.span,
46+
&format!("self-assignment of `{}` to `{}`", rhs, lhs),
47+
);
48+
}
49+
}
50+
}
51+
}

src/lintlist/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,6 +1956,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
19561956
deprecation: None,
19571957
module: "methods",
19581958
},
1959+
Lint {
1960+
name: "self_assignment",
1961+
group: "correctness",
1962+
desc: "explicit self-assignment",
1963+
deprecation: None,
1964+
module: "self_assignment",
1965+
},
19591966
Lint {
19601967
name: "serde_api_misuse",
19611968
group: "correctness",

tests/ui/self_assignment.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#![warn(clippy::self_assignment)]
2+
3+
pub struct S<'a> {
4+
a: i32,
5+
b: [i32; 10],
6+
c: Vec<Vec<i32>>,
7+
e: &'a mut i32,
8+
f: &'a mut i32,
9+
}
10+
11+
pub fn positives(mut a: usize, b: &mut u32, mut s: S) {
12+
a = a;
13+
*b = *b;
14+
s = s;
15+
s.a = s.a;
16+
s.b[10] = s.b[5 + 5];
17+
s.c[0][1] = s.c[0][1];
18+
s.b[a] = s.b[a];
19+
*s.e = *s.e;
20+
s.b[a + 10] = s.b[10 + a];
21+
22+
let mut t = (0, 1);
23+
t.1 = t.1;
24+
t.0 = (t.0);
25+
}
26+
27+
pub fn negatives_not_equal(mut a: usize, b: &mut usize, mut s: S) {
28+
dbg!(&a);
29+
a = *b;
30+
dbg!(&a);
31+
s.b[1] += s.b[1];
32+
s.b[1] = s.b[2];
33+
s.c[1][0] = s.c[0][1];
34+
s.b[a] = s.b[*b];
35+
s.b[a + 10] = s.b[a + 11];
36+
*s.e = *s.f;
37+
38+
let mut t = (0, 1);
39+
t.0 = t.1;
40+
}
41+
42+
#[allow(clippy::eval_order_dependence)]
43+
pub fn negatives_side_effects() {
44+
let mut v = vec![1, 2, 3, 4, 5];
45+
let mut i = 0;
46+
v[{
47+
i += 1;
48+
i
49+
}] = v[{
50+
i += 1;
51+
i
52+
}];
53+
54+
fn next(n: &mut usize) -> usize {
55+
let v = *n;
56+
*n += 1;
57+
v
58+
}
59+
60+
let mut w = vec![1, 2, 3, 4, 5];
61+
let mut i = 0;
62+
let i = &mut i;
63+
w[next(i)] = w[next(i)];
64+
w[next(i)] = w[next(i)];
65+
}
66+
67+
fn main() {}

tests/ui/self_assignment.stderr

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
error: self-assignment of `a` to `a`
2+
--> $DIR/self_assignment.rs:12:5
3+
|
4+
LL | a = a;
5+
| ^^^^^
6+
|
7+
= note: `-D clippy::self-assignment` implied by `-D warnings`
8+
9+
error: self-assignment of `*b` to `*b`
10+
--> $DIR/self_assignment.rs:13:5
11+
|
12+
LL | *b = *b;
13+
| ^^^^^^^
14+
15+
error: self-assignment of `s` to `s`
16+
--> $DIR/self_assignment.rs:14:5
17+
|
18+
LL | s = s;
19+
| ^^^^^
20+
21+
error: self-assignment of `s.a` to `s.a`
22+
--> $DIR/self_assignment.rs:15:5
23+
|
24+
LL | s.a = s.a;
25+
| ^^^^^^^^^
26+
27+
error: self-assignment of `s.b[5 + 5]` to `s.b[10]`
28+
--> $DIR/self_assignment.rs:16:5
29+
|
30+
LL | s.b[10] = s.b[5 + 5];
31+
| ^^^^^^^^^^^^^^^^^^^^
32+
33+
error: self-assignment of `s.c[0][1]` to `s.c[0][1]`
34+
--> $DIR/self_assignment.rs:17:5
35+
|
36+
LL | s.c[0][1] = s.c[0][1];
37+
| ^^^^^^^^^^^^^^^^^^^^^
38+
39+
error: self-assignment of `s.b[a]` to `s.b[a]`
40+
--> $DIR/self_assignment.rs:18:5
41+
|
42+
LL | s.b[a] = s.b[a];
43+
| ^^^^^^^^^^^^^^^
44+
45+
error: self-assignment of `*s.e` to `*s.e`
46+
--> $DIR/self_assignment.rs:19:5
47+
|
48+
LL | *s.e = *s.e;
49+
| ^^^^^^^^^^^
50+
51+
error: self-assignment of `s.b[10 + a]` to `s.b[a + 10]`
52+
--> $DIR/self_assignment.rs:20:5
53+
|
54+
LL | s.b[a + 10] = s.b[10 + a];
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
56+
57+
error: self-assignment of `t.1` to `t.1`
58+
--> $DIR/self_assignment.rs:23:5
59+
|
60+
LL | t.1 = t.1;
61+
| ^^^^^^^^^
62+
63+
error: self-assignment of `(t.0)` to `t.0`
64+
--> $DIR/self_assignment.rs:24:5
65+
|
66+
LL | t.0 = (t.0);
67+
| ^^^^^^^^^^^
68+
69+
error: aborting due to 11 previous errors
70+

0 commit comments

Comments
 (0)