diff --git a/CHANGELOG.md b/CHANGELOG.md index 272f5d77f350..0ad943c3f8a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. ## Unreleased -* New lint: [`temporary_cstring_as_ptr`] and [`unsafe_removed_from_name`] +* New lints: [`temporary_cstring_as_ptr`], [`unsafe_removed_from_name`], and [`mem_forget`] ## 0.0.63 — 2016-04-08 * Rustup to *rustc 1.9.0-nightly (7979dd608 2016-04-07)* @@ -135,6 +135,7 @@ All notable changes to this project will be documented in this file. [`match_overlapping_arm`]: https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm [`match_ref_pats`]: https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats [`match_same_arms`]: https://github.com/Manishearth/rust-clippy/wiki#match_same_arms +[`mem_forget`]: https://github.com/Manishearth/rust-clippy/wiki#mem_forget [`min_max`]: https://github.com/Manishearth/rust-clippy/wiki#min_max [`modulo_one`]: https://github.com/Manishearth/rust-clippy/wiki#modulo_one [`mut_mut`]: https://github.com/Manishearth/rust-clippy/wiki#mut_mut diff --git a/README.md b/README.md index 6aa1e1ecf340..d55536c033d8 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 143 lints included in this crate: +There are 144 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -85,6 +85,7 @@ name [match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match has overlapping arms [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead [match_same_arms](https://github.com/Manishearth/rust-clippy/wiki#match_same_arms) | warn | `match` with identical arm bodies +[mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | `mem::forget` usage on `Drop` types is likely to cause memory leaks [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) diff --git a/src/lib.rs b/src/lib.rs index 5774f3bf7af4..5f3b3999f951 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,6 +79,7 @@ pub mod lifetimes; pub mod loops; pub mod map_clone; pub mod matches; +pub mod mem_forget; pub mod methods; pub mod minmax; pub mod misc; @@ -236,6 +237,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents)); reg.register_late_lint_pass(box neg_multiply::NegMultiply); reg.register_late_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval); + reg.register_late_lint_pass(box mem_forget::MemForget); reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, @@ -243,6 +245,7 @@ pub fn plugin_registrar(reg: &mut Registry) { enum_glob_use::ENUM_GLOB_USE, if_not_else::IF_NOT_ELSE, matches::SINGLE_MATCH_ELSE, + mem_forget::MEM_FORGET, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::WRONG_PUB_SELF_CONVENTION, diff --git a/src/mem_forget.rs b/src/mem_forget.rs new file mode 100644 index 000000000000..1f627d614ff3 --- /dev/null +++ b/src/mem_forget.rs @@ -0,0 +1,44 @@ +use rustc::lint::*; +use rustc::hir::{Expr, ExprCall, ExprPath}; +use utils::{match_def_path, paths, span_lint}; + +/// **What it does:** This lint checks for usage of `std::mem::forget(t)` where `t` is `Drop`. +/// +/// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks +/// +/// **Known problems:** None. +/// +/// **Example:** `mem::forget(Rc::new(55)))` +declare_lint! { + pub MEM_FORGET, + Allow, + "`mem::forget` usage on `Drop` types is likely to cause memory leaks" +} + +pub struct MemForget; + +impl LintPass for MemForget { + fn get_lints(&self) -> LintArray { + lint_array![MEM_FORGET] + } +} + +impl LateLintPass for MemForget { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprCall(ref path_expr, ref args) = e.node { + if let ExprPath(None, _) = path_expr.node { + let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); + if match_def_path(cx, def_id, &paths::MEM_FORGET) { + let forgot_ty = cx.tcx.expr_ty(&args[0]); + + if match forgot_ty.ty_adt_def() { + Some(def) => def.has_dtor(), + _ => false + } { + span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); + } + } + } + } + } +} diff --git a/src/utils/paths.rs b/src/utils/paths.rs index 88d0dd415aad..38985373085b 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -20,6 +20,7 @@ pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "Ha pub const HASH: [&'static str; 2] = ["hash", "Hash"]; pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"]; pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"]; pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPTION: [&'static str; 3] = ["core", "option", "Option"]; diff --git a/tests/compile-fail/mem_forget.rs b/tests/compile-fail/mem_forget.rs new file mode 100644 index 000000000000..c8cebcb2a42d --- /dev/null +++ b/tests/compile-fail/mem_forget.rs @@ -0,0 +1,28 @@ +#![feature(plugin)] +#![plugin(clippy)] + +use std::sync::Arc; +use std::rc::Rc; + +use std::mem::forget as forgetSomething; +use std::mem as memstuff; + +#[deny(mem_forget)] +fn main() { + let five: i32 = 5; + forgetSomething(five); + + let six: Arc = Arc::new(6); + memstuff::forget(six); + //~^ ERROR usage of mem::forget on Drop type + + let seven: Rc = Rc::new(7); + std::mem::forget(seven); + //~^ ERROR usage of mem::forget on Drop type + + let eight: Vec = vec![8]; + forgetSomething(eight); + //~^ ERROR usage of mem::forget on Drop type + + std::mem::forget(7); +}