diff --git a/CHANGELOG.md b/CHANGELOG.md index d0d7893a1..22b503746 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Change Log All notable changes to this project will be documented in this file. +* New [`zero_ptr`] lint * New [`never_loop`] lint * New [`mut_from_ref`] lint @@ -474,5 +475,6 @@ All notable changes to this project will be documented in this file. [`wrong_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute [`zero_divided_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero [`zero_prefixed_literal`]: https://github.com/Manishearth/rust-clippy/wiki#zero_prefixed_literal +[`zero_ptr`]: https://github.com/Manishearth/rust-clippy/wiki#zero_ptr [`zero_width_space`]: https://github.com/Manishearth/rust-clippy/wiki#zero_width_space diff --git a/README.md b/README.md index 2c9e7e3da..36ea7e401 100644 --- a/README.md +++ b/README.md @@ -376,6 +376,7 @@ name [wrong_transmute](https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute) | warn | transmutes that are confusing at best, undefined behaviour at worst and always useless [zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN [zero_prefixed_literal](https://github.com/Manishearth/rust-clippy/wiki#zero_prefixed_literal) | warn | integer literals starting with `0` +[zero_ptr](https://github.com/Manishearth/rust-clippy/wiki#zero_ptr) | warn | using 0 as *{const, mut} T [zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 542847dc1..31b2e2342 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -452,6 +452,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { misc_early::REDUNDANT_CLOSURE_CALL, misc_early::UNNEEDED_FIELD_PATTERN, misc_early::ZERO_PREFIXED_LITERAL, + misc_early::ZERO_PTR, mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, needless_bool::BOOL_COMPARISON, diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 0e4b0db33..f9de6a011 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -162,6 +162,23 @@ declare_lint! { "shadowing a builtin type" } +/// **What it does:** Catch casts from `0` to some pointer type +/// +/// **Why is this bad?** This generally means `null` and is better expressed as +/// {`std`, `core`}`::ptr::`{`null`, `null_mut`}. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// +/// ```rust +/// 0 as *const u32 +/// ``` +declare_lint! { + pub ZERO_PTR, + Warn, + "using 0 as *{const, mut} T" +} #[derive(Copy, Clone)] pub struct MiscEarly; @@ -175,7 +192,8 @@ impl LintPass for MiscEarly { MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, ZERO_PREFIXED_LITERAL, - BUILTIN_TYPE_SHADOW) + BUILTIN_TYPE_SHADOW, + ZERO_PTR) } } @@ -363,6 +381,9 @@ impl EarlyLintPass for MiscEarly { } }} }, + ExprKind::Cast(ref e, ref ty) => { + check_cast(cx, expr.span, e, ty); + }, _ => (), } } @@ -391,3 +412,18 @@ impl EarlyLintPass for MiscEarly { } } } + +fn check_cast(cx: &EarlyContext, span: Span, e: &Expr, ty: &Ty) { + if_let_chain! {[ + let TyKind::Ptr(MutTy { mutbl, .. }) = ty.node, + let ExprKind::Lit(ref lit) = e.node, + let LitKind::Int(value, ..) = lit.node, + value == 0 + ], { + let msg = match mutbl { + Mutability::Mutable => "`0 as *mut _` detected. Consider using `ptr::null_mut()`", + Mutability::Immutable => "`0 as *const _` detected. Consider using `ptr::null()`", + }; + span_lint(cx, ZERO_PTR, span, msg); + }} +} diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 1fae47c8a..6f0a831f5 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -91,7 +91,7 @@ fn issue1231() { bar: &'a T, } - let raw = 0 as *const i32; + let raw = 42 as *const i32; let _: &Foo = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; @@ -103,7 +103,7 @@ fn issue1231() { type Bar<'a> = &'a u8; - let raw = 0 as *const i32; + let raw = 42 as *const i32; unsafe { std::mem::transmute::<_, Bar>(raw) }; diff --git a/tests/ui/zero_ptr.rs b/tests/ui/zero_ptr.rs new file mode 100644 index 000000000..a72223ef5 --- /dev/null +++ b/tests/ui/zero_ptr.rs @@ -0,0 +1,11 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[allow(unused_variables)] +fn main() { + let x = 0 as *const usize; + let y = 0 as *mut f64; + + let z = 0; + let z = z as *const usize; // this is currently not caught +} diff --git a/tests/ui/zero_ptr.stderr b/tests/ui/zero_ptr.stderr new file mode 100644 index 000000000..e17a3bfb2 --- /dev/null +++ b/tests/ui/zero_ptr.stderr @@ -0,0 +1,16 @@ +warning: `0 as *const _` detected. Consider using `ptr::null()` + --> $DIR/zero_ptr.rs:6:13 + | +6 | let x = 0 as *const usize; + | ^^^^^^^^^^^^^^^^^ + | + = note: #[warn(zero_ptr)] on by default + +warning: `0 as *mut _` detected. Consider using `ptr::null_mut()` + --> $DIR/zero_ptr.rs:7:13 + | +7 | let y = 0 as *mut f64; + | ^^^^^^^^^^^^^ + | + = note: #[warn(zero_ptr)] on by default +