]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/mut_key.rs
Auto merge of #4809 - iankronquist:patch-1, r=flip1995
[rust.git] / clippy_lints / src / mut_key.rs
index 3a0899032a566ea871712e3de1ac2cd35d1642ff..d48c4c419aef58b0399cdc519b484773efb67b35 100644 (file)
@@ -1,10 +1,9 @@
 use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty};
-use rustc::declare_lint_pass;
-use rustc::hir;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::ty::{Adt, Dynamic, Opaque, Param, RawPtr, Ref, Ty, TypeAndMut};
-use rustc_session::declare_tool_lint;
-use syntax::source_map::Span;
+use rustc::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut};
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Span;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for sets/maps with mutable key types.
@@ -47,7 +46,7 @@
     /// ```
     pub MUTABLE_KEY_TYPE,
     correctness,
-    "Check for mutable Map/Set key type"
+    "Check for mutable `Map`/`Set` key type"
 }
 
 declare_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]);
@@ -73,7 +72,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Trai
         }
     }
 
-    fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &hir::Local) {
+    fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &hir::Local<'_>) {
         if let hir::PatKind::Wild = local.pat.kind {
             return;
         }
@@ -81,7 +80,7 @@ fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &hir::Local) {
     }
 }
 
-fn check_sig<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item_hir_id: hir::HirId, decl: &hir::FnDecl) {
+fn check_sig<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) {
     let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id);
     let fn_sig = cx.tcx.fn_sig(fn_def_id);
     for (hir_ty, ty) in decl.inputs.iter().zip(fn_sig.inputs().skip_binder().iter()) {
@@ -102,19 +101,24 @@ fn check_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) {
         if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET]
             .iter()
             .any(|path| match_def_path(cx, def.did, &**path))
+            && is_mutable_type(cx, substs.type_at(0), span)
         {
-            let key_type = substs.type_at(0);
-            if is_concrete_type(key_type) && !key_type.is_freeze(cx.tcx, cx.param_env, span) {
-                span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
-            }
+            span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
         }
     }
 }
 
-fn is_concrete_type(ty: Ty<'_>) -> bool {
+fn is_mutable_type<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
     match ty.kind {
-        RawPtr(TypeAndMut { ty: inner_ty, .. }) | Ref(_, inner_ty, _) => is_concrete_type(inner_ty),
-        Dynamic(..) | Opaque(..) | Param(..) => false,
-        _ => true,
+        RawPtr(TypeAndMut { ty: inner_ty, mutbl }) | Ref(_, inner_ty, mutbl) => {
+            mutbl == hir::Mutability::Mut || is_mutable_type(cx, inner_ty, span)
+        },
+        Slice(inner_ty) => is_mutable_type(cx, inner_ty, span),
+        Array(inner_ty, size) => {
+            size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) && is_mutable_type(cx, inner_ty, span)
+        },
+        Tuple(..) => ty.tuple_fields().any(|ty| is_mutable_type(cx, ty, span)),
+        Adt(..) => cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env, span),
+        _ => false,
     }
 }