11use clippy_utils:: diagnostics:: span_lint;
2- use clippy_utils:: ty:: is_interior_mut_ty;
3- use clippy_utils:: { def_path_def_ids, trait_ref_of_method} ;
4- use rustc_data_structures:: fx:: FxHashSet ;
2+ use clippy_utils:: trait_ref_of_method;
3+ use clippy_utils:: ty:: InteriorMut ;
54use rustc_hir as hir;
65use rustc_lint:: { LateContext , LateLintPass } ;
76use rustc_middle:: ty:: { self , Ty } ;
@@ -23,41 +22,28 @@ declare_clippy_lint! {
2322 /// ### Known problems
2423 ///
2524 /// #### False Positives
26- /// It's correct to use a struct that contains interior mutability as a key, when its
25+ /// It's correct to use a struct that contains interior mutability as a key when its
2726 /// implementation of `Hash` or `Ord` doesn't access any of the interior mutable types.
2827 /// However, this lint is unable to recognize this, so it will often cause false positives in
29- /// theses cases. The `bytes` crate is a great example of this .
28+ /// these cases.
3029 ///
3130 /// #### False Negatives
32- /// For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind
33- /// indirection. For example, `struct BadKey<'a>(&'a Cell<usize>)` will be seen as immutable
34- /// and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`.
35- ///
36- /// This lint does check a few cases for indirection. Firstly, using some standard library
37- /// types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and
38- /// `BTreeSet`) directly as keys (e.g. in `HashMap<Box<Cell<usize>>, ()>`) **will** trigger the
39- /// lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their
40- /// contained type.
41- ///
42- /// Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`)
43- /// apply only to the **address** of the contained value. Therefore, interior mutability
44- /// behind raw pointers (e.g. in `HashSet<*mut Cell<usize>>`) can't impact the value of `Hash`
45- /// or `Ord`, and therefore will not trigger this link. For more info, see issue
46- /// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745).
31+ /// This lint does not follow raw pointers (`*const T` or `*mut T`) as `Hash` and `Ord`
32+ /// apply only to the **address** of the contained value. This can cause false negatives for
33+ /// custom collections that use raw pointers internally.
4734 ///
4835 /// ### Example
4936 /// ```no_run
5037 /// use std::cmp::{PartialEq, Eq};
5138 /// use std::collections::HashSet;
5239 /// use std::hash::{Hash, Hasher};
5340 /// use std::sync::atomic::AtomicUsize;
54- ///# #[allow(unused)]
5541 ///
5642 /// struct Bad(AtomicUsize);
5743 /// impl PartialEq for Bad {
5844 /// fn eq(&self, rhs: &Self) -> bool {
5945 /// ..
60- /// ; unimplemented!();
46+ /// # ; true
6147 /// }
6248 /// }
6349 ///
@@ -66,7 +52,7 @@ declare_clippy_lint! {
6652 /// impl Hash for Bad {
6753 /// fn hash<H: Hasher>(&self, h: &mut H) {
6854 /// ..
69- /// ; unimplemented!() ;
55+ /// # ;
7056 /// }
7157 /// }
7258 ///
@@ -80,25 +66,16 @@ declare_clippy_lint! {
8066 "Check for mutable `Map`/`Set` key type"
8167}
8268
83- #[ derive( Clone ) ]
84- pub struct MutableKeyType {
69+ pub struct MutableKeyType < ' tcx > {
8570 ignore_interior_mutability : Vec < String > ,
86- ignore_mut_def_ids : FxHashSet < hir :: def_id :: DefId > ,
71+ interior_mut : InteriorMut < ' tcx > ,
8772}
8873
89- impl_lint_pass ! ( MutableKeyType => [ MUTABLE_KEY_TYPE ] ) ;
74+ impl_lint_pass ! ( MutableKeyType < ' _> => [ MUTABLE_KEY_TYPE ] ) ;
9075
91- impl < ' tcx > LateLintPass < ' tcx > for MutableKeyType {
76+ impl < ' tcx > LateLintPass < ' tcx > for MutableKeyType < ' tcx > {
9277 fn check_crate ( & mut self , cx : & LateContext < ' tcx > ) {
93- self . ignore_mut_def_ids . clear ( ) ;
94- let mut path = Vec :: new ( ) ;
95- for ty in & self . ignore_interior_mutability {
96- path. extend ( ty. split ( "::" ) ) ;
97- for id in def_path_def_ids ( cx, & path[ ..] ) {
98- self . ignore_mut_def_ids . insert ( id) ;
99- }
100- path. clear ( ) ;
101- }
78+ self . interior_mut = InteriorMut :: without_pointers ( cx, & self . ignore_interior_mutability ) ;
10279 }
10380
10481 fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: Item < ' tcx > ) {
@@ -121,23 +98,23 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
12198 }
12299 }
123100
124- fn check_local ( & mut self , cx : & LateContext < ' _ > , local : & hir:: LetStmt < ' _ > ) {
101+ fn check_local ( & mut self , cx : & LateContext < ' tcx > , local : & hir:: LetStmt < ' tcx > ) {
125102 if let hir:: PatKind :: Wild = local. pat . kind {
126103 return ;
127104 }
128105 self . check_ty_ ( cx, local. span , cx. typeck_results ( ) . pat_ty ( local. pat ) ) ;
129106 }
130107}
131108
132- impl MutableKeyType {
109+ impl < ' tcx > MutableKeyType < ' tcx > {
133110 pub fn new ( ignore_interior_mutability : Vec < String > ) -> Self {
134111 Self {
135112 ignore_interior_mutability,
136- ignore_mut_def_ids : FxHashSet :: default ( ) ,
113+ interior_mut : InteriorMut :: default ( ) ,
137114 }
138115 }
139116
140- fn check_sig ( & self , cx : & LateContext < ' _ > , fn_def_id : LocalDefId , decl : & hir:: FnDecl < ' _ > ) {
117+ fn check_sig ( & mut self , cx : & LateContext < ' tcx > , fn_def_id : LocalDefId , decl : & hir:: FnDecl < ' tcx > ) {
141118 let fn_sig = cx. tcx . fn_sig ( fn_def_id) . instantiate_identity ( ) ;
142119 for ( hir_ty, ty) in iter:: zip ( decl. inputs , fn_sig. inputs ( ) . skip_binder ( ) ) {
143120 self . check_ty_ ( cx, hir_ty. span , * ty) ;
@@ -151,7 +128,7 @@ impl MutableKeyType {
151128
152129 // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
153130 // generics (because the compiler cannot ensure immutability for unknown types).
154- fn check_ty_ < ' tcx > ( & self , cx : & LateContext < ' tcx > , span : Span , ty : Ty < ' tcx > ) {
131+ fn check_ty_ ( & mut self , cx : & LateContext < ' tcx > , span : Span , ty : Ty < ' tcx > ) {
155132 let ty = ty. peel_refs ( ) ;
156133 if let ty:: Adt ( def, args) = ty. kind ( ) {
157134 let is_keyed_type = [ sym:: HashMap , sym:: BTreeMap , sym:: HashSet , sym:: BTreeSet ]
@@ -162,11 +139,7 @@ impl MutableKeyType {
162139 }
163140
164141 let subst_ty = args. type_at ( 0 ) ;
165- // Determines if a type contains interior mutability which would affect its implementation of
166- // [`Hash`] or [`Ord`].
167- if is_interior_mut_ty ( cx, subst_ty)
168- && !matches ! ( subst_ty. ty_adt_def( ) , Some ( adt) if self . ignore_mut_def_ids. contains( & adt. did( ) ) )
169- {
142+ if self . interior_mut . is_interior_mut_ty ( cx, subst_ty) {
170143 span_lint ( cx, MUTABLE_KEY_TYPE , span, "mutable key type" ) ;
171144 }
172145 }
0 commit comments