From a6c4eaa93c7400450facd0eb0580e4d641f2e297 Mon Sep 17 00:00:00 2001
From: Konrad Borowski <konrad@borowski.pw>
Date: Sun, 30 Dec 2018 02:43:56 +0100
Subject: [PATCH 1/3] random_state lint

---
 CHANGELOG.md                     |  1 +
 README.md                        |  2 +-
 clippy_lints/src/lib.rs          |  3 ++
 clippy_lints/src/random_state.rs | 48 ++++++++++++++++++++++++++++++++
 clippy_lints/src/utils/paths.rs  |  1 +
 tests/ui/random_state.rs         | 19 +++++++++++++
 tests/ui/random_state.stderr     | 28 +++++++++++++++++++
 7 files changed, 101 insertions(+), 1 deletion(-)
 create mode 100644 clippy_lints/src/random_state.rs
 create mode 100644 tests/ui/random_state.rs
 create mode 100644 tests/ui/random_state.stderr

diff --git a/CHANGELOG.md b/CHANGELOG.md
index efa637b185cd..b5c8feb8ac65 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -814,6 +814,7 @@ All notable changes to this project will be documented in this file.
 [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
 [`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
+[`random_state`]: https://rust-lang.github.io/rust-clippy/master/index.html#random_state
 [`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
 [`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
 [`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
diff --git a/README.md b/README.md
index 626b589b5f3e..be24f1be8272 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are 290 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)
 
 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 27905b917500..0aa9ff5985f4 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -180,6 +180,7 @@ pub mod precedence;
 pub mod ptr;
 pub mod ptr_offset_with_cast;
 pub mod question_mark;
+pub mod random_state;
 pub mod ranges;
 pub mod redundant_clone;
 pub mod redundant_field_names;
@@ -484,6 +485,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 random_state::Pass);
 
     reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![
         arithmetic::FLOAT_ARITHMETIC,
@@ -1023,6 +1025,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
         fallible_impl_from::FALLIBLE_IMPL_FROM,
         mutex_atomic::MUTEX_INTEGER,
         needless_borrow::NEEDLESS_BORROW,
+        random_state::RANDOM_STATE,
         redundant_clone::REDUNDANT_CLONE,
         unwrap::PANICKING_UNWRAP,
         unwrap::UNNECESSARY_UNWRAP,
diff --git a/clippy_lints/src/random_state.rs b/clippy_lints/src/random_state.rs
new file mode 100644
index 000000000000..02abd2e93bd7
--- /dev/null
+++ b/clippy_lints/src/random_state.rs
@@ -0,0 +1,48 @@
+use crate::utils::{match_type, paths, span_lint};
+use rustc::hir::Ty;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty::subst::UnpackedKind;
+use rustc::ty::TyKind;
+use rustc::{declare_tool_lint, lint_array};
+
+/// **What it does:** Checks for usage of `RandomState`
+///
+/// **Why is this bad?** Some applications don't need collision prevention
+/// which lowers the performance.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+/// ```rust
+/// fn x() {
+///     let mut map = std::collections::HashMap::new();
+///     map.insert(3, 4);
+/// }
+/// ```
+declare_clippy_lint! {
+    pub RANDOM_STATE,
+    nursery,
+    "use of RandomState"
+}
+
+pub struct Pass;
+
+impl LintPass for Pass {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(RANDOM_STATE)
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+    fn check_ty(&mut self, cx: &LateContext<'a, 'tcx>, ty: &Ty) {
+        if let TyKind::Adt(_, substs) = cx.tables.node_id_to_type(ty.hir_id).sty {
+            for subst in substs {
+                if let UnpackedKind::Type(build_hasher) = subst.unpack() {
+                    if match_type(cx, build_hasher, &paths::RANDOM_STATE) {
+                        span_lint(cx, RANDOM_STATE, ty.span, "usage of RandomState");
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs
index 0779d77936f5..0ec684e36bca 100644
--- a/clippy_lints/src/utils/paths.rs
+++ b/clippy_lints/src/utils/paths.rs
@@ -73,6 +73,7 @@ pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
 pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
 pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
 pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
+pub const RANDOM_STATE: [&str; 5] = ["std", "collections", "hash", "map", "RandomState"];
 pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
 pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
diff --git a/tests/ui/random_state.rs b/tests/ui/random_state.rs
new file mode 100644
index 000000000000..31f4b4d49b46
--- /dev/null
+++ b/tests/ui/random_state.rs
@@ -0,0 +1,19 @@
+#![warn(clippy::random_state)]
+
+use std::collections::hash_map::RandomState;
+use std::collections::hash_map::{DefaultHasher, HashMap};
+use std::hash::{BuildHasherDefault};
+
+fn main() {
+    // Should warn
+    let mut map = HashMap::new();
+    map.insert(3, 4);
+    let mut map = HashMap::with_hasher(RandomState::new());
+    map.insert(true, false);
+    let _map: HashMap<_, _> = vec![(2, 3)].into_iter().collect();
+    let _vec: Vec<HashMap<i32, i32>>;
+    // Shouldn't warn
+    let _map: HashMap<i32, i32, BuildHasherDefault<DefaultHasher>> = HashMap::default();
+    let mut map = HashMap::with_hasher(BuildHasherDefault::<DefaultHasher>::default());
+    map.insert("a", "b");
+}
diff --git a/tests/ui/random_state.stderr b/tests/ui/random_state.stderr
new file mode 100644
index 000000000000..df224bf0c298
--- /dev/null
+++ b/tests/ui/random_state.stderr
@@ -0,0 +1,28 @@
+error: usage of RandomState
+  --> $DIR/random_state.rs:9:19
+   |
+LL |     let mut map = HashMap::new();
+   |                   ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::random-state` implied by `-D warnings`
+
+error: usage of RandomState
+  --> $DIR/random_state.rs:11:19
+   |
+LL |     let mut map = HashMap::with_hasher(RandomState::new());
+   |                   ^^^^^^^^^^^^^^^^^^^^
+
+error: usage of RandomState
+  --> $DIR/random_state.rs:13:15
+   |
+LL |     let _map: HashMap<_, _> = vec![(2, 3)].into_iter().collect();
+   |               ^^^^^^^^^^^^^
+
+error: usage of RandomState
+  --> $DIR/random_state.rs:14:19
+   |
+LL |     let _vec: Vec<HashMap<i32, i32>>;
+   |                   ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+

From 978e3ac2cfac8cb62147d2ed6992cbcbf37bb45f Mon Sep 17 00:00:00 2001
From: Konrad Borowski <konrad@borowski.pw>
Date: Sun, 30 Dec 2018 13:40:27 +0100
Subject: [PATCH 2/3] Use node_id_to_type_opt instead of node_it_to_type in
 random_state

---
 clippy_lints/src/random_state.rs | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/clippy_lints/src/random_state.rs b/clippy_lints/src/random_state.rs
index 02abd2e93bd7..f95116c04b6d 100644
--- a/clippy_lints/src/random_state.rs
+++ b/clippy_lints/src/random_state.rs
@@ -35,11 +35,13 @@ impl LintPass for Pass {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
     fn check_ty(&mut self, cx: &LateContext<'a, 'tcx>, ty: &Ty) {
-        if let TyKind::Adt(_, substs) = cx.tables.node_id_to_type(ty.hir_id).sty {
-            for subst in substs {
-                if let UnpackedKind::Type(build_hasher) = subst.unpack() {
-                    if match_type(cx, build_hasher, &paths::RANDOM_STATE) {
-                        span_lint(cx, RANDOM_STATE, ty.span, "usage of RandomState");
+        if let Some(tys) = cx.tables.node_id_to_type_opt(ty.hir_id) {
+            if let TyKind::Adt(_, substs) = tys.sty {
+                for subst in substs {
+                    if let UnpackedKind::Type(build_hasher) = subst.unpack() {
+                        if match_type(cx, build_hasher, &paths::RANDOM_STATE) {
+                            span_lint(cx, RANDOM_STATE, ty.span, "usage of RandomState");
+                        }
                     }
                 }
             }

From 11b957e18d36c348279295ad056a1a535d8e9780 Mon Sep 17 00:00:00 2001
From: Konrad Borowski <konrad@borowski.pw>
Date: Sun, 30 Dec 2018 14:29:43 +0100
Subject: [PATCH 3/3] Reformat random_state tests

---
 tests/ui/random_state.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/ui/random_state.rs b/tests/ui/random_state.rs
index 31f4b4d49b46..f4fa85997a82 100644
--- a/tests/ui/random_state.rs
+++ b/tests/ui/random_state.rs
@@ -2,7 +2,7 @@
 
 use std::collections::hash_map::RandomState;
 use std::collections::hash_map::{DefaultHasher, HashMap};
-use std::hash::{BuildHasherDefault};
+use std::hash::BuildHasherDefault;
 
 fn main() {
     // Should warn