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;
}
```
This commit is contained in:
Tomasz Miąsko 2020-08-16 00:00:00 +00:00
parent d1dbf7913a
commit 4f4abf4e06
6 changed files with 201 additions and 0 deletions

View file

@ -284,6 +284,7 @@ mod reference;
mod regex;
mod repeat_once;
mod returns;
mod self_assignment;
mod serde_api;
mod shadow;
mod single_component_path_imports;
@ -773,6 +774,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&repeat_once::REPEAT_ONCE,
&returns::LET_AND_RETURN,
&returns::NEEDLESS_RETURN,
&self_assignment::SELF_ASSIGNMENT,
&serde_api::SERDE_API_MISUSE,
&shadow::SHADOW_REUSE,
&shadow::SHADOW_SAME,
@ -1090,6 +1092,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
store.register_late_pass(|| box repeat_once::RepeatOnce);
store.register_late_pass(|| box self_assignment::SelfAssignment);
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@ -1421,6 +1424,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&repeat_once::REPEAT_ONCE),
LintId::of(&returns::LET_AND_RETURN),
LintId::of(&returns::NEEDLESS_RETURN),
LintId::of(&self_assignment::SELF_ASSIGNMENT),
LintId::of(&serde_api::SERDE_API_MISUSE),
LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
@ -1714,6 +1718,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&ptr::MUT_FROM_REF),
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
LintId::of(&regex::INVALID_REGEX),
LintId::of(&self_assignment::SELF_ASSIGNMENT),
LintId::of(&serde_api::SERDE_API_MISUSE),
LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),

View file

@ -0,0 +1,51 @@
use crate::utils::{eq_expr_value, snippet, span_lint};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
/// **What it does:** Checks for explicit self-assignments.
///
/// **Why is this bad?** Self-assignments are redundant and unlikely to be
/// intentional.
///
/// **Known problems:** If expression contains any deref coercions or
/// indexing operations they are assumed not to have any side effects.
///
/// **Example:**
///
/// ```rust
/// struct Event {
/// id: usize,
/// x: i32,
/// y: i32,
/// }
///
/// fn copy_position(a: &mut Event, b: &Event) {
/// a.x = b.x;
/// a.y = a.y;
/// }
/// ```
pub SELF_ASSIGNMENT,
correctness,
"explicit self-assignment"
}
declare_lint_pass!(SelfAssignment => [SELF_ASSIGNMENT]);
impl<'tcx> LateLintPass<'tcx> for SelfAssignment {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Assign(lhs, rhs, _) = &expr.kind {
if eq_expr_value(cx, lhs, rhs) {
let lhs = snippet(cx, lhs.span, "<lhs>");
let rhs = snippet(cx, rhs.span, "<rhs>");
span_lint(
cx,
SELF_ASSIGNMENT,
expr.span,
&format!("self-assignment of `{}` to `{}`", rhs, lhs),
);
}
}
}
}