Avoid mut_key on types of unknown layout
This commit is contained in:
parent
f728bcd431
commit
59fd637ba1
@ -1,5 +1,5 @@
|
|||||||
use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty};
|
use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty};
|
||||||
use rustc::ty::{Adt, Dynamic, Opaque, Param, RawPtr, Ref, Ty, TypeAndMut};
|
use rustc::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
@ -101,21 +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]
|
if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET]
|
||||||
.iter()
|
.iter()
|
||||||
.any(|path| match_def_path(cx, def.did, &**path))
|
.any(|path| match_def_path(cx, def.did, &**path))
|
||||||
|
&& is_mutable_type(cx, substs.type_at(0), span)
|
||||||
{
|
{
|
||||||
let key_type = concrete_type(substs.type_at(0));
|
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
|
||||||
if let Some(key_type) = key_type {
|
|
||||||
if !key_type.is_freeze(cx.tcx, cx.param_env, span) {
|
|
||||||
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn concrete_type(ty: Ty<'_>) -> Option<Ty<'_>> {
|
fn is_mutable_type<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
|
||||||
match ty.kind {
|
match ty.kind {
|
||||||
RawPtr(TypeAndMut { ty: inner_ty, .. }) | Ref(_, inner_ty, _) => concrete_type(inner_ty),
|
RawPtr(TypeAndMut { ty: inner_ty, mutbl }) | Ref(_, inner_ty, mutbl) => {
|
||||||
Dynamic(..) | Opaque(..) | Param(..) => None,
|
mutbl == hir::Mutability::Mut || is_mutable_type(cx, inner_ty, span)
|
||||||
_ => Some(ty),
|
},
|
||||||
|
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![allow(clippy::implicit_hasher)]
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
|
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
|
||||||
@ -29,9 +31,27 @@ fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<K
|
|||||||
m.keys().cloned().collect()
|
m.keys().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn this_is_ok(m: &mut HashMap<usize, Key>) {}
|
fn this_is_ok(_m: &mut HashMap<usize, Key>) {}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
trait Trait {
|
||||||
|
type AssociatedType;
|
||||||
|
|
||||||
|
fn trait_fn(&self, set: std::collections::HashSet<Self::AssociatedType>);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generics_are_ok_too<K>(_m: &mut HashSet<K>) {
|
||||||
|
// nothing to see here, move along
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuples<U>(_m: &mut HashMap<((), U), ()>) {}
|
||||||
|
|
||||||
|
fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = should_not_take_this_arg(&mut HashMap::new(), 1);
|
let _ = should_not_take_this_arg(&mut HashMap::new(), 1);
|
||||||
this_is_ok(&mut HashMap::new());
|
this_is_ok(&mut HashMap::new());
|
||||||
|
tuples::<Key>(&mut HashMap::new());
|
||||||
|
tuples::<()>(&mut HashMap::new());
|
||||||
|
tuples_bad::<()>(&mut HashMap::new());
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:27:32
|
--> $DIR/mut_key.rs:29:32
|
||||||
|
|
|
|
||||||
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> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -7,16 +7,22 @@ LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> Hash
|
|||||||
= note: `#[deny(clippy::mutable_key_type)]` on by default
|
= note: `#[deny(clippy::mutable_key_type)]` on by default
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:27:72
|
--> $DIR/mut_key.rs:29:72
|
||||||
|
|
|
|
||||||
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> {
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: mutable key type
|
error: mutable key type
|
||||||
--> $DIR/mut_key.rs:28:5
|
--> $DIR/mut_key.rs:30:5
|
||||||
|
|
|
|
||||||
LL | let _other: HashMap<Key, bool> = HashMap::new();
|
LL | let _other: HashMap<Key, bool> = HashMap::new();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: mutable key type
|
||||||
|
--> $DIR/mut_key.rs:49:22
|
||||||
|
|
|
||||||
|
LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user