]> git.lizzy.rs Git - rust.git/commitdiff
New lint for assignment to temporary
authorSeo Sanghyeon <sanxiyn@gmail.com>
Wed, 4 Nov 2015 09:55:14 +0000 (18:55 +0900)
committerSeo Sanghyeon <sanxiyn@gmail.com>
Wed, 4 Nov 2015 12:37:18 +0000 (21:37 +0900)
README.md
src/lib.rs
src/temporary_assignment.rs [new file with mode: 0644]
tests/compile-fail/temporary_assignment.rs [new file with mode: 0644]

index 4c23d6994d298fc9ed2cc7829f2e41b20b027422..5a2ea945349326bd08a02835ad0f24c44bbb624b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code.
 [Jump to usage instructions](#usage)
 
 ##Lints
-There are 72 lints included in this crate:
+There are 73 lints included in this crate:
 
 name                                                                                                   | default | meaning
 -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -68,6 +68,7 @@ name
 [string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add)                               | allow   | using `x + ..` where x is a `String`; suggests using `push_str()` instead
 [string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign)                 | allow   | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead
 [string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string)                   | warn    | calling `String.to_string()` which is a no-op
+[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment)           | warn    | assignments to temporaries
 [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg)                   | warn    | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`.
 [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity)                     | warn    | usage of very complex types; recommends factoring out parts into `type` definitions
 [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc)                     | allow   | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information)
index 37e1ace61ded590091d440c70023a058c08f28a4..970a244e2cd7c8dc6c37dc85a32cff8287e165fb 100755 (executable)
@@ -54,6 +54,7 @@
 pub mod needless_features;
 pub mod needless_update;
 pub mod no_effect;
+pub mod temporary_assignment;
 
 mod reexport {
     pub use syntax::ast::{Name, Ident, NodeId};
@@ -102,6 +103,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
     reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass);
     reg.register_late_lint_pass(box no_effect::NoEffectPass);
     reg.register_late_lint_pass(box map_clone::MapClonePass);
+    reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass);
 
     reg.register_lint_group("clippy_pedantic", vec![
         methods::OPTION_UNWRAP_USED,
@@ -172,6 +174,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
         ranges::RANGE_ZIP_WITH_LEN,
         returns::LET_AND_RETURN,
         returns::NEEDLESS_RETURN,
+        temporary_assignment::TEMPORARY_ASSIGNMENT,
         types::BOX_VEC,
         types::LET_UNIT_VALUE,
         types::LINKEDLIST,
diff --git a/src/temporary_assignment.rs b/src/temporary_assignment.rs
new file mode 100644 (file)
index 0000000..6cfcb71
--- /dev/null
@@ -0,0 +1,44 @@
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc_front::hir::{Expr, ExprAssign, ExprField, ExprStruct, ExprTup, ExprTupField};
+
+use utils::is_adjusted;
+use utils::span_lint;
+
+declare_lint! {
+    pub TEMPORARY_ASSIGNMENT,
+    Warn,
+    "assignments to temporaries"
+}
+
+fn is_temporary(expr: &Expr) -> bool {
+    match expr.node {
+        ExprStruct(..) |
+        ExprTup(..) => true,
+        _ => false,
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct TemporaryAssignmentPass;
+
+impl LintPass for TemporaryAssignmentPass {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(TEMPORARY_ASSIGNMENT)
+    }
+}
+
+impl LateLintPass for TemporaryAssignmentPass {
+    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
+        if let ExprAssign(ref target, _) = expr.node {
+            match target.node {
+                ExprField(ref base, _) | ExprTupField(ref base, _) => {
+                    if is_temporary(base) && !is_adjusted(cx, base) {
+                        span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span,
+                                  "assignment to temporary");
+                    }
+                }
+                _ => ()
+            }
+        }
+    }
+}
diff --git a/tests/compile-fail/temporary_assignment.rs b/tests/compile-fail/temporary_assignment.rs
new file mode 100644 (file)
index 0000000..b1c2b99
--- /dev/null
@@ -0,0 +1,36 @@
+#![feature(plugin)]
+#![plugin(clippy)]
+
+#![deny(temporary_assignment)]
+
+use std::ops::{Deref, DerefMut};
+
+struct Struct {
+    field: i32
+}
+
+struct Wrapper<'a> {
+    inner: &'a mut Struct
+}
+
+impl<'a> Deref for Wrapper<'a> {
+    type Target = Struct;
+    fn deref(&self) -> &Struct { self.inner }
+}
+
+impl<'a> DerefMut for Wrapper<'a> {
+    fn deref_mut(&mut self) -> &mut Struct { self.inner }
+}
+
+fn main() {
+    let mut s = Struct { field: 0 };
+    let mut t = (0, 0);
+
+    Struct { field: 0 }.field = 1; //~ERROR assignment to temporary
+    (0, 0).0 = 1; //~ERROR assignment to temporary
+
+    // no error
+    s.field = 1;
+    t.0 = 1;
+    Wrapper { inner: &mut s }.field = 1;
+}