about summary refs log tree commit diff
path: root/clippy_lints
diff options
context:
space:
mode:
authorTomasz Miąsko <tomasz.miasko@gmail.com>2020-08-16 00:00:00 +0000
committerTomasz Miąsko <tomasz.miasko@gmail.com>2020-08-16 23:31:36 +0200
commit4f4abf4e0640edbb1614f3dcb8ff62e8afc54801 (patch)
treed44d58b8093ea749dd64d37f188c41a9bc7a9e1c /clippy_lints
parentd1dbf7913ad83954337e94b094f22f1d9d8b83f3 (diff)
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;
}
```
Diffstat (limited to 'clippy_lints')
-rw-r--r--clippy_lints/src/lib.rs5
-rw-r--r--clippy_lints/src/self_assignment.rs51
2 files changed, 56 insertions, 0 deletions
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 17501e8e6da..87c297e72eb 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -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),
diff --git a/clippy_lints/src/self_assignment.rs b/clippy_lints/src/self_assignment.rs
new file mode 100644
index 00000000000..e096c9aebc1
--- /dev/null
+++ b/clippy_lints/src/self_assignment.rs
@@ -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),
+                );
+            }
+        }
+    }
+}