1
1
use 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 ;
5
4
use rustc_hir as hir;
6
5
use rustc_lint:: { LateContext , LateLintPass } ;
7
6
use rustc_middle:: ty:: { self , Ty } ;
@@ -23,41 +22,28 @@ declare_clippy_lint! {
23
22
/// ### Known problems
24
23
///
25
24
/// #### 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
27
26
/// implementation of `Hash` or `Ord` doesn't access any of the interior mutable types.
28
27
/// 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.
30
29
///
31
30
/// #### 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.
47
34
///
48
35
/// ### Example
49
36
/// ```no_run
50
37
/// use std::cmp::{PartialEq, Eq};
51
38
/// use std::collections::HashSet;
52
39
/// use std::hash::{Hash, Hasher};
53
40
/// use std::sync::atomic::AtomicUsize;
54
- ///# #[allow(unused)]
55
41
///
56
42
/// struct Bad(AtomicUsize);
57
43
/// impl PartialEq for Bad {
58
44
/// fn eq(&self, rhs: &Self) -> bool {
59
45
/// ..
60
- /// ; unimplemented!();
46
+ /// # ; true
61
47
/// }
62
48
/// }
63
49
///
@@ -66,7 +52,7 @@ declare_clippy_lint! {
66
52
/// impl Hash for Bad {
67
53
/// fn hash<H: Hasher>(&self, h: &mut H) {
68
54
/// ..
69
- /// ; unimplemented!() ;
55
+ /// # ;
70
56
/// }
71
57
/// }
72
58
///
@@ -80,25 +66,16 @@ declare_clippy_lint! {
80
66
"Check for mutable `Map`/`Set` key type"
81
67
}
82
68
83
- #[ derive( Clone ) ]
84
- pub struct MutableKeyType {
69
+ pub struct MutableKeyType < ' tcx > {
85
70
ignore_interior_mutability : Vec < String > ,
86
- ignore_mut_def_ids : FxHashSet < hir :: def_id :: DefId > ,
71
+ interior_mut : InteriorMut < ' tcx > ,
87
72
}
88
73
89
- impl_lint_pass ! ( MutableKeyType => [ MUTABLE_KEY_TYPE ] ) ;
74
+ impl_lint_pass ! ( MutableKeyType < ' _> => [ MUTABLE_KEY_TYPE ] ) ;
90
75
91
- impl < ' tcx > LateLintPass < ' tcx > for MutableKeyType {
76
+ impl < ' tcx > LateLintPass < ' tcx > for MutableKeyType < ' tcx > {
92
77
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 ) ;
102
79
}
103
80
104
81
fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: Item < ' tcx > ) {
@@ -121,23 +98,23 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
121
98
}
122
99
}
123
100
124
- fn check_local ( & mut self , cx : & LateContext < ' _ > , local : & hir:: LetStmt < ' _ > ) {
101
+ fn check_local ( & mut self , cx : & LateContext < ' tcx > , local : & hir:: LetStmt < ' tcx > ) {
125
102
if let hir:: PatKind :: Wild = local. pat . kind {
126
103
return ;
127
104
}
128
105
self . check_ty_ ( cx, local. span , cx. typeck_results ( ) . pat_ty ( local. pat ) ) ;
129
106
}
130
107
}
131
108
132
- impl MutableKeyType {
109
+ impl < ' tcx > MutableKeyType < ' tcx > {
133
110
pub fn new ( ignore_interior_mutability : Vec < String > ) -> Self {
134
111
Self {
135
112
ignore_interior_mutability,
136
- ignore_mut_def_ids : FxHashSet :: default ( ) ,
113
+ interior_mut : InteriorMut :: default ( ) ,
137
114
}
138
115
}
139
116
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 > ) {
141
118
let fn_sig = cx. tcx . fn_sig ( fn_def_id) . instantiate_identity ( ) ;
142
119
for ( hir_ty, ty) in iter:: zip ( decl. inputs , fn_sig. inputs ( ) . skip_binder ( ) ) {
143
120
self . check_ty_ ( cx, hir_ty. span , * ty) ;
@@ -151,7 +128,7 @@ impl MutableKeyType {
151
128
152
129
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
153
130
// 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 > ) {
155
132
let ty = ty. peel_refs ( ) ;
156
133
if let ty:: Adt ( def, args) = ty. kind ( ) {
157
134
let is_keyed_type = [ sym:: HashMap , sym:: BTreeMap , sym:: HashSet , sym:: BTreeSet ]
@@ -162,11 +139,7 @@ impl MutableKeyType {
162
139
}
163
140
164
141
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) {
170
143
span_lint ( cx, MUTABLE_KEY_TYPE , span, "mutable key type" ) ;
171
144
}
172
145
}
0 commit comments