mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-24 05:33:27 +00:00
print cause chain in mutable_key_type
This commit is contained in:
parent
db1bda3df1
commit
19d1358b31
3 changed files with 98 additions and 23 deletions
|
@ -1,9 +1,10 @@
|
||||||
use clippy_config::Conf;
|
use clippy_config::Conf;
|
||||||
use clippy_utils::diagnostics::span_lint;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::trait_ref_of_method;
|
use clippy_utils::trait_ref_of_method;
|
||||||
use clippy_utils::ty::InteriorMut;
|
use clippy_utils::ty::InteriorMut;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_session::impl_lint_pass;
|
use rustc_session::impl_lint_pass;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -132,8 +133,14 @@ impl<'tcx> MutableKeyType<'tcx> {
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
let subst_ty = args.type_at(0);
|
let subst_ty = args.type_at(0);
|
||||||
if self.interior_mut.is_interior_mut_ty(cx, subst_ty) {
|
if let Some(chain) = self.interior_mut.interior_mut_ty_chain(cx, subst_ty) {
|
||||||
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
|
span_lint_and_then(cx, MUTABLE_KEY_TYPE, span, "mutable key type", |diag| {
|
||||||
|
for ty in chain.iter().rev() {
|
||||||
|
diag.note(with_forced_trimmed_paths!(format!(
|
||||||
|
"... because it contains `{ty}`, which has interior mutability"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1168,7 +1168,7 @@ pub fn make_normalized_projection<'tcx>(
|
||||||
pub struct InteriorMut<'tcx> {
|
pub struct InteriorMut<'tcx> {
|
||||||
ignored_def_ids: FxHashSet<DefId>,
|
ignored_def_ids: FxHashSet<DefId>,
|
||||||
ignore_pointers: bool,
|
ignore_pointers: bool,
|
||||||
tys: FxHashMap<Ty<'tcx>, Option<bool>>,
|
tys: FxHashMap<Ty<'tcx>, Option<&'tcx ty::List<Ty<'tcx>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> InteriorMut<'tcx> {
|
impl<'tcx> InteriorMut<'tcx> {
|
||||||
|
@ -1194,25 +1194,24 @@ impl<'tcx> InteriorMut<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if given type has inner mutability such as [`std::cell::Cell`] or
|
/// Check if given type has interior mutability such as [`std::cell::Cell`] or
|
||||||
/// [`std::cell::RefCell`] etc.
|
/// [`std::cell::RefCell`] etc. and if it does, returns a chain of types that causes
|
||||||
pub fn is_interior_mut_ty(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
/// this type to be interior mutable
|
||||||
|
pub fn interior_mut_ty_chain(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx ty::List<Ty<'tcx>>> {
|
||||||
match self.tys.entry(ty) {
|
match self.tys.entry(ty) {
|
||||||
Entry::Occupied(o) => return *o.get() == Some(true),
|
Entry::Occupied(o) => return *o.get(),
|
||||||
// Temporarily insert a `None` to break cycles
|
// Temporarily insert a `None` to break cycles
|
||||||
Entry::Vacant(v) => v.insert(None),
|
Entry::Vacant(v) => v.insert(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
let interior_mut = match *ty.kind() {
|
let chain = match *ty.kind() {
|
||||||
ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.is_interior_mut_ty(cx, inner_ty),
|
ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.interior_mut_ty_chain(cx, inner_ty),
|
||||||
ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.is_interior_mut_ty(cx, inner_ty),
|
ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.interior_mut_ty_chain(cx, inner_ty),
|
||||||
ty::Array(inner_ty, size) => {
|
ty::Array(inner_ty, size) if size.try_eval_target_usize(cx.tcx, cx.param_env) != Some(0) => {
|
||||||
size.try_eval_target_usize(cx.tcx, cx.param_env)
|
self.interior_mut_ty_chain(cx, inner_ty)
|
||||||
.map_or(true, |u| u != 0)
|
|
||||||
&& self.is_interior_mut_ty(cx, inner_ty)
|
|
||||||
},
|
},
|
||||||
ty::Tuple(fields) => fields.iter().any(|ty| self.is_interior_mut_ty(cx, ty)),
|
ty::Tuple(fields) => fields.iter().find_map(|ty| self.interior_mut_ty_chain(cx, ty)),
|
||||||
ty::Adt(def, _) if def.is_unsafe_cell() => true,
|
ty::Adt(def, _) if def.is_unsafe_cell() => Some(ty::List::empty()),
|
||||||
ty::Adt(def, args) => {
|
ty::Adt(def, args) => {
|
||||||
let is_std_collection = matches!(
|
let is_std_collection = matches!(
|
||||||
cx.tcx.get_diagnostic_name(def.did()),
|
cx.tcx.get_diagnostic_name(def.did()),
|
||||||
|
@ -1231,19 +1230,28 @@ impl<'tcx> InteriorMut<'tcx> {
|
||||||
|
|
||||||
if is_std_collection || def.is_box() {
|
if is_std_collection || def.is_box() {
|
||||||
// Include the types from std collections that are behind pointers internally
|
// Include the types from std collections that are behind pointers internally
|
||||||
args.types().any(|ty| self.is_interior_mut_ty(cx, ty))
|
args.types().find_map(|ty| self.interior_mut_ty_chain(cx, ty))
|
||||||
} else if self.ignored_def_ids.contains(&def.did()) || def.is_phantom_data() {
|
} else if self.ignored_def_ids.contains(&def.did()) || def.is_phantom_data() {
|
||||||
false
|
None
|
||||||
} else {
|
} else {
|
||||||
def.all_fields()
|
def.all_fields()
|
||||||
.any(|f| self.is_interior_mut_ty(cx, f.ty(cx.tcx, args)))
|
.find_map(|f| self.interior_mut_ty_chain(cx, f.ty(cx.tcx, args)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.tys.insert(ty, Some(interior_mut));
|
chain.map(|chain| {
|
||||||
interior_mut
|
let list = cx.tcx.mk_type_list_from_iter(chain.iter().chain([ty]));
|
||||||
|
self.tys.insert(ty, Some(list));
|
||||||
|
list
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if given type has interior mutability such as [`std::cell::Cell`] or
|
||||||
|
/// [`std::cell::RefCell`] etc.
|
||||||
|
pub fn is_interior_mut_ty(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
|
self.interior_mut_ty_chain(cx, ty).is_some()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ error: mutable key type
|
||||||
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
|
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
|
= note: ... because it contains `Key`, which has interior mutability
|
||||||
|
= note: ... because it contains `AtomicUsize`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
= note: `-D clippy::mutable-key-type` implied by `-D warnings`
|
= note: `-D clippy::mutable-key-type` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::mutable_key_type)]`
|
= help: to override `-D warnings` add `#[allow(clippy::mutable_key_type)]`
|
||||||
|
|
||||||
|
@ -12,84 +15,141 @@ error: mutable key type
|
||||||
|
|
|
|
||||||
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
|
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `Key`, which has interior mutability
|
||||||
|
= note: ... because it contains `AtomicUsize`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:35:5
|
--> tests/ui/mut_key.rs:35:5
|
||||||
|
|
|
|
||||||
LL | let _other: HashMap<Key, bool> = HashMap::new();
|
LL | let _other: HashMap<Key, bool> = HashMap::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `Key`, which has interior mutability
|
||||||
|
= note: ... because it contains `AtomicUsize`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:63:22
|
--> tests/ui/mut_key.rs:63:22
|
||||||
|
|
|
|
||||||
LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
|
LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `(Key, U)`, which has interior mutability
|
||||||
|
= note: ... because it contains `Key`, which has interior mutability
|
||||||
|
= note: ... because it contains `AtomicUsize`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:76:5
|
--> tests/ui/mut_key.rs:76:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Cell<usize>, usize>::new();
|
LL | let _map = HashMap::<Cell<usize>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:78:5
|
--> tests/ui/mut_key.rs:78:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<&mut Cell<usize>, usize>::new();
|
LL | let _map = HashMap::<&mut Cell<usize>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `&mut Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:81:5
|
--> tests/ui/mut_key.rs:81:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Vec<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Vec<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `Vec<Cell<usize>>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:83:5
|
--> tests/ui/mut_key.rs:83:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<BTreeMap<Cell<usize>, ()>, usize>::new();
|
LL | let _map = HashMap::<BTreeMap<Cell<usize>, ()>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `BTreeMap<Cell<usize>, ()>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:85:5
|
--> tests/ui/mut_key.rs:85:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<BTreeMap<(), Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<BTreeMap<(), Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `BTreeMap<(), Cell<usize>>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:87:5
|
--> tests/ui/mut_key.rs:87:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<BTreeSet<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<BTreeSet<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `BTreeSet<Cell<usize>>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:89:5
|
--> tests/ui/mut_key.rs:89:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Option<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Option<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `Option<Cell<usize>>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:91:5
|
--> tests/ui/mut_key.rs:91:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Option<Vec<Cell<usize>>>, usize>::new();
|
LL | let _map = HashMap::<Option<Vec<Cell<usize>>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `Option<Vec<Cell<usize>>>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Vec<Cell<usize>>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:94:5
|
--> tests/ui/mut_key.rs:94:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Box<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Box<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `Box<Cell<usize>>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:96:5
|
--> tests/ui/mut_key.rs:96:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Rc<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Rc<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `Rc<Cell<usize>>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> tests/ui/mut_key.rs:98:5
|
--> tests/ui/mut_key.rs:98:5
|
||||||
|
|
|
|
||||||
LL | let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
|
LL | let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ... because it contains `Arc<Cell<usize>>`, which has interior mutability
|
||||||
|
= note: ... because it contains `Cell<usize>`, which has interior mutability
|
||||||
|
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
|
||||||
|
|
||||||
error: aborting due to 15 previous errors
|
error: aborting due to 15 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue