about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--README.md6
-rw-r--r--clippy_lints/src/lib.rs3
-rw-r--r--clippy_lints/src/new_without_default.rs2
-rw-r--r--clippy_lints/src/types.rs61
-rw-r--r--clippy_lints/src/use_self.rs18
-rw-r--r--tests/ui/cast_ref_to_mut.rs31
-rw-r--r--tests/ui/cast_ref_to_mut.stderr22
-rw-r--r--tests/ui/use_self.rs39
-rw-r--r--tests/ui/use_self.stderr14
10 files changed, 173 insertions, 24 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 69d0350eb09..14c1b0e4d3f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -635,6 +635,7 @@ All notable changes to this project will be documented in this file.
 [`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap
 [`cast_precision_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_precision_loss
 [`cast_ptr_alignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ptr_alignment
+[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
 [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
diff --git a/README.md b/README.md
index 751f0add8eb..8ca10da416d 100644
--- a/README.md
+++ b/README.md
@@ -7,13 +7,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-<<<<<<< HEAD
 [There are 291 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
-||||||| merged common ancestors
-[There are 291 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
-=======
-[There are 291 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
->>>>>>> run ./util/dev update_lints
 
 We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
 
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 192c9226b69..1c362313e77 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -487,6 +487,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
     reg.register_late_lint_pass(box ptr_offset_with_cast::Pass);
     reg.register_late_lint_pass(box redundant_clone::RedundantClone);
     reg.register_late_lint_pass(box slow_vector_initialization::Pass);
+    reg.register_late_lint_pass(box types::RefToMut);
     reg.register_late_lint_pass(box assertions_on_constants::AssertionsOnConstants);
 
     reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![
@@ -761,6 +762,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
         types::BOX_VEC,
         types::CAST_LOSSLESS,
         types::CAST_PTR_ALIGNMENT,
+        types::CAST_REF_TO_MUT,
         types::CHAR_LIT_AS_U8,
         types::FN_TO_NUMERIC_CAST,
         types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
@@ -993,6 +995,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
         transmute::WRONG_TRANSMUTE,
         types::ABSURD_EXTREME_COMPARISONS,
         types::CAST_PTR_ALIGNMENT,
+        types::CAST_REF_TO_MUT,
         types::UNIT_CMP,
         unicode::ZERO_WIDTH_SPACE,
         unused_io_amount::UNUSED_IO_AMOUNT,
diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs
index 917a80b81f6..832311dc027 100644
--- a/clippy_lints/src/new_without_default.rs
+++ b/clippy_lints/src/new_without_default.rs
@@ -27,7 +27,7 @@ use syntax::source_map::Span;
 /// It detects both the case when a manual
 /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
 /// implementation is required and also when it can be created with
-/// `#[derive(Default)]
+/// `#[derive(Default)]`
 ///
 /// **Why is this bad?** The user might expect to be able to use
 /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs
index f4ca8209d67..f9ed38e52a0 100644
--- a/clippy_lints/src/types.rs
+++ b/clippy_lints/src/types.rs
@@ -2240,3 +2240,64 @@ impl<'a, 'b, 'tcx: 'a + 'b> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'
         NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
     }
 }
+
+/// **What it does:** Checks for casts of `&T` to `&mut T` anywhere in the code.
+///
+/// **Why is this bad?** It’s basically guaranteed to be undefined behaviour.
+/// `UnsafeCell` is the only way to obtain aliasable data that is considered
+/// mutable.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+/// ```rust
+/// fn x(r: &i32) {
+///     unsafe {
+///         *(r as *const _ as *mut _) += 1;
+///     }
+/// }
+/// ```
+///
+/// Instead consider using interior mutability types.
+///
+/// ```rust
+/// fn x(r: &UnsafeCell<i32>) {
+///     unsafe {
+///         *r.get() += 1;
+///     }
+/// }
+/// ```
+declare_clippy_lint! {
+    pub CAST_REF_TO_MUT,
+    correctness,
+    "a cast of reference to a mutable pointer"
+}
+
+pub struct RefToMut;
+
+impl LintPass for RefToMut {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(CAST_REF_TO_MUT)
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RefToMut {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        if_chain! {
+            if let ExprKind::Unary(UnOp::UnDeref, e) = &expr.node;
+            if let ExprKind::Cast(e, t) = &e.node;
+            if let TyKind::Ptr(MutTy { mutbl: Mutability::MutMutable, .. }) = t.node;
+            if let ExprKind::Cast(e, t) = &e.node;
+            if let TyKind::Ptr(MutTy { mutbl: Mutability::MutImmutable, .. }) = t.node;
+            if let ty::Ref(..) = cx.tables.node_id_to_type(e.hir_id).sty;
+            then {
+                span_lint(
+                    cx,
+                    CAST_REF_TO_MUT,
+                    expr.span,
+                    "casting &T to &mut T may cause undefined behaviour, consider instead using an UnsafeCell",
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs
index aa4302e12a7..5ec809f1b76 100644
--- a/clippy_lints/src/use_self.rs
+++ b/clippy_lints/src/use_self.rs
@@ -10,13 +10,12 @@
 use crate::utils::span_lint_and_sugg;
 use if_chain::if_chain;
 use rustc::hir::def::{CtorKind, Def};
-use rustc::hir::intravisit::{walk_path, walk_ty, NestedVisitorMap, Visitor};
+use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
 use rustc::hir::*;
 use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty;
 use rustc::{declare_tool_lint, lint_array};
 use rustc_errors::Applicability;
-use syntax::ast::NodeId;
 use syntax_pos::symbol::keywords::SelfUpper;
 
 /// **What it does:** Checks for unnecessary repetition of structure name when a
@@ -29,7 +28,6 @@ use syntax_pos::symbol::keywords::SelfUpper;
 /// **Known problems:**
 /// - False positive when using associated types (#2843)
 /// - False positives in some situations when using generics (#3410)
-/// - False positive when type from outer function can't be used (#3463)
 ///
 /// **Example:**
 /// ```rust
@@ -242,8 +240,18 @@ impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
         walk_path(self, path);
     }
 
-    fn visit_use(&mut self, _path: &'tcx Path, _id: NodeId, _hir_id: HirId) {
-        // Don't check use statements
+    fn visit_item(&mut self, item: &'tcx Item) {
+        match item.node {
+            ItemKind::Use(..)
+            | ItemKind::Static(..)
+            | ItemKind::Enum(..)
+            | ItemKind::Struct(..)
+            | ItemKind::Union(..)
+            | ItemKind::Impl(..) => {
+                // Don't check statements that shadow `Self` or where `Self` can't be used
+            },
+            _ => walk_item(self, item),
+        }
     }
 
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
diff --git a/tests/ui/cast_ref_to_mut.rs b/tests/ui/cast_ref_to_mut.rs
new file mode 100644
index 00000000000..967e8e46739
--- /dev/null
+++ b/tests/ui/cast_ref_to_mut.rs
@@ -0,0 +1,31 @@
+#![warn(clippy::cast_ref_to_mut)]
+#![allow(clippy::no_effect)]
+
+extern "C" {
+    // NB. Mutability can be easily incorrect in FFI calls, as
+    // in C, the default are mutable pointers.
+    fn ffi(c: *mut u8);
+    fn int_ffi(c: *mut i32);
+}
+
+fn main() {
+    let s = String::from("Hello");
+    let a = &s;
+    unsafe {
+        let num = &3i32;
+        let mut_num = &mut 3i32;
+        // Should be warned against
+        (*(a as *const _ as *mut String)).push_str(" world");
+        *(a as *const _ as *mut _) = String::from("Replaced");
+        *(a as *const _ as *mut String) += " world";
+        // Shouldn't be warned against
+        println!("{}", *(num as *const _ as *const i16));
+        println!("{}", *(mut_num as *mut _ as *mut i16));
+        ffi(a.as_ptr() as *mut _);
+        int_ffi(num as *const _ as *mut _);
+        int_ffi(&3 as *const _ as *mut _);
+        let mut value = 3;
+        let value: *const i32 = &mut value;
+        *(value as *const i16 as *mut i16) = 42;
+    }
+}
diff --git a/tests/ui/cast_ref_to_mut.stderr b/tests/ui/cast_ref_to_mut.stderr
new file mode 100644
index 00000000000..448a66cfcce
--- /dev/null
+++ b/tests/ui/cast_ref_to_mut.stderr
@@ -0,0 +1,22 @@
+error: casting &T to &mut T may cause undefined behaviour, consider instead using an UnsafeCell
+  --> $DIR/cast_ref_to_mut.rs:18:9
+   |
+LL |         (*(a as *const _ as *mut String)).push_str(" world");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-ref-to-mut` implied by `-D warnings`
+
+error: casting &T to &mut T may cause undefined behaviour, consider instead using an UnsafeCell
+  --> $DIR/cast_ref_to_mut.rs:19:9
+   |
+LL |         *(a as *const _ as *mut _) = String::from("Replaced");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting &T to &mut T may cause undefined behaviour, consider instead using an UnsafeCell
+  --> $DIR/cast_ref_to_mut.rs:20:9
+   |
+LL |         *(a as *const _ as *mut String) += " world";
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs
index a01cb3e7021..a117ce5894b 100644
--- a/tests/ui/use_self.rs
+++ b/tests/ui/use_self.rs
@@ -242,6 +242,34 @@ mod macros {
     }
 }
 
+mod nesting {
+    struct Foo {}
+    impl Foo {
+        fn foo() {
+            use self::Foo; // Can't use Self here
+            struct Bar {
+                foo: Foo, // Foo != Self
+            }
+
+            impl Bar {
+                fn bar() -> Bar {
+                    Bar { foo: Foo {} }
+                }
+            }
+        }
+    }
+
+    enum Enum {
+        A,
+    }
+    impl Enum {
+        fn method() {
+            use self::Enum::*; // Issue 3425
+            static STATIC: Enum = Enum::A; // Can't use Self as type
+        }
+    }
+}
+
 mod issue3410 {
 
     struct A;
@@ -255,14 +283,3 @@ mod issue3410 {
         fn a(_: Vec<A>) {}
     }
 }
-
-mod issue3425 {
-    enum Enum {
-        A,
-    }
-    impl Enum {
-        fn a() {
-            use self::Enum::*;
-        }
-    }
-}
diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr
index 6c5dbf9111d..72b60db7fd2 100644
--- a/tests/ui/use_self.stderr
+++ b/tests/ui/use_self.stderr
@@ -150,5 +150,17 @@ LL |                 Foo {}
 LL |         use_self_expand!(); // Should lint in local macros
    |         ------------------- in this macro invocation
 
-error: aborting due to 24 previous errors
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:255:29
+   |
+LL |                 fn bar() -> Bar {
+   |                             ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:256:21
+   |
+LL |                     Bar { foo: Foo {} }
+   |                     ^^^ help: use the applicable keyword: `Self`
+
+error: aborting due to 26 previous errors