Skip to content

Commit 6aa4530

Browse files
committed
extract is_interior_mutable_type from [mut_key] to clippy_utils::ty;
fix configuration of [`ifs_same_cond`]; add some style improvement for [`ifs_same_cond`];
1 parent b180be9 commit 6aa4530

File tree

7 files changed

+102
-82
lines changed

7 files changed

+102
-82
lines changed

clippy_lints/src/copies.rs

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
22
use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt};
3-
use clippy_utils::ty::needs_ordered_drop;
3+
use clippy_utils::ty::{is_interior_mut_ty, needs_ordered_drop};
44
use clippy_utils::visitors::for_each_expr;
55
use clippy_utils::{
66
capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt,
@@ -164,12 +164,14 @@ declare_clippy_lint! {
164164

165165
pub struct CopyAndPaste {
166166
ignore_interior_mutability: Vec<String>,
167+
ignored_ty_ids: FxHashSet<DefId>,
167168
}
168169

169170
impl CopyAndPaste {
170171
pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
171172
Self {
172173
ignore_interior_mutability,
174+
ignored_ty_ids: FxHashSet::default(),
173175
}
174176
}
175177
}
@@ -182,17 +184,18 @@ impl_lint_pass!(CopyAndPaste => [
182184
]);
183185

184186
impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
187+
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
188+
for ignored_ty in &self.ignore_interior_mutability {
189+
let path: Vec<&str> = ignored_ty.split("::").collect();
190+
for id in def_path_def_ids(cx, path.as_slice()) {
191+
self.ignored_ty_ids.insert(id);
192+
}
193+
}
194+
}
185195
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
186196
if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) {
187197
let (conds, blocks) = if_sequence(expr);
188-
let mut ignored_ty_ids = FxHashSet::default();
189-
for ignored_ty in &self.ignore_interior_mutability {
190-
let path: Vec<&str> = ignored_ty.split("::").collect();
191-
for id in def_path_def_ids(cx, path.as_slice()) {
192-
ignored_ty_ids.insert(id);
193-
}
194-
}
195-
lint_same_cond(cx, &conds, &ignored_ty_ids);
198+
lint_same_cond(cx, &conds, &self.ignored_ty_ids);
196199
lint_same_fns_in_if_cond(cx, &conds);
197200
let all_same =
198201
!is_lint_allowed(cx, IF_SAME_THEN_ELSE, expr.hir_id) && lint_if_same_then_else(cx, &conds, &blocks);
@@ -569,28 +572,18 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
569572
})
570573
}
571574

572-
fn method_caller_is_ignored_or_mutable(
573-
cx: &LateContext<'_>,
574-
caller_expr: &Expr<'_>,
575-
ignored_ty_ids: &FxHashSet<DefId>,
576-
) -> bool {
575+
fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignored_ty_ids: &FxHashSet<DefId>) -> bool {
577576
let caller_ty = cx.typeck_results().expr_ty(caller_expr);
578-
let is_ignored_ty = if let Some(adt_id) = caller_ty.ty_adt_id() && ignored_ty_ids.contains(&adt_id) {
579-
true
580-
} else {
581-
false
582-
};
577+
// Check if given type has inner mutability and was not set to ignored by the configuration
578+
let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty)
579+
&& !matches!(caller_ty.ty_adt_id(), Some(adt_id) if ignored_ty_ids.contains(&adt_id));
583580

584-
if is_ignored_ty
581+
is_inner_mut_ty
585582
|| caller_ty.is_mutable_ptr()
583+
// `find_binding_init` will return the binding iff its not mutable
586584
|| path_to_local(caller_expr)
587585
.and_then(|hid| find_binding_init(cx, hid))
588586
.is_none()
589-
{
590-
return true;
591-
}
592-
593-
false
594587
}
595588

596589
/// Implementation of `IFS_SAME_COND`.
@@ -599,8 +592,10 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &Fx
599592
conds,
600593
|e| hash_expr(cx, e),
601594
|lhs, rhs| {
595+
// Ignore eq_expr side effects iff one of the expressin kind is a method call
596+
// and the caller is not a mutable, including inner mutable type.
602597
if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind {
603-
if method_caller_is_ignored_or_mutable(cx, caller, ignored_ty_ids) {
598+
if method_caller_is_mutable(cx, caller, ignored_ty_ids) {
604599
false
605600
} else {
606601
SpanlessEq::new(cx).eq_expr(lhs, rhs)

clippy_lints/src/mut_key.rs

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::ty::is_interior_mut_ty;
23
use clippy_utils::{def_path_def_ids, trait_ref_of_method};
34
use rustc_data_structures::fx::FxHashSet;
45
use rustc_hir as hir;
56
use rustc_lint::{LateContext, LateLintPass};
6-
use rustc_middle::ty::TypeVisitable;
7-
use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
7+
use rustc_middle::query::Key;
8+
use rustc_middle::ty::{Adt, Ty};
89
use rustc_session::{declare_tool_lint, impl_lint_pass};
910
use rustc_span::def_id::LocalDefId;
1011
use rustc_span::source_map::Span;
@@ -153,52 +154,18 @@ impl MutableKeyType {
153154
let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
154155
.iter()
155156
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
156-
if is_keyed_type && self.is_interior_mutable_type(cx, substs.type_at(0)) {
157-
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
157+
if !is_keyed_type {
158+
return;
158159
}
159-
}
160-
}
161160

162-
/// Determines if a type contains interior mutability which would affect its implementation of
163-
/// [`Hash`] or [`Ord`].
164-
fn is_interior_mutable_type<'tcx>(&self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
165-
match *ty.kind() {
166-
Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty),
167-
Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty),
168-
Array(inner_ty, size) => {
169-
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
170-
&& self.is_interior_mutable_type(cx, inner_ty)
171-
},
172-
Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
173-
Adt(def, substs) => {
174-
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
175-
// that of their type parameters. Note: we don't include `HashSet` and `HashMap`
176-
// because they have no impl for `Hash` or `Ord`.
177-
let def_id = def.did();
178-
let is_std_collection = [
179-
sym::Option,
180-
sym::Result,
181-
sym::LinkedList,
182-
sym::Vec,
183-
sym::VecDeque,
184-
sym::BTreeMap,
185-
sym::BTreeSet,
186-
sym::Rc,
187-
sym::Arc,
188-
]
189-
.iter()
190-
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id));
191-
let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
192-
if is_std_collection || is_box || self.ignore_mut_def_ids.contains(&def_id) {
193-
// The type is mutable if any of its type parameters are
194-
substs.types().any(|ty| self.is_interior_mutable_type(cx, ty))
195-
} else {
196-
!ty.has_escaping_bound_vars()
197-
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
198-
&& !ty.is_freeze(cx.tcx, cx.param_env)
199-
}
200-
},
201-
_ => false,
161+
let subst_ty = substs.type_at(0);
162+
// Determines if a type contains interior mutability which would affect its implementation of
163+
// [`Hash`] or [`Ord`].
164+
if is_interior_mut_ty(cx, subst_ty)
165+
&& !matches!(subst_ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id))
166+
{
167+
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
168+
}
202169
}
203170
}
204171
}

clippy_utils/src/ty.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,3 +1108,44 @@ pub fn make_normalized_projection<'tcx>(
11081108
}
11091109
helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?)
11101110
}
1111+
1112+
/// Check if given type has inner mutability such as [`Cell`] or [`Arc`] etc.
1113+
pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
1114+
match *ty.kind() {
1115+
ty::Ref(_, inner_ty, mutbl) => mutbl == Mutability::Mut || is_interior_mut_ty(cx, inner_ty),
1116+
ty::Slice(inner_ty) => is_interior_mut_ty(cx, inner_ty),
1117+
ty::Array(inner_ty, size) => {
1118+
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) && is_interior_mut_ty(cx, inner_ty)
1119+
},
1120+
ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)),
1121+
ty::Adt(def, substs) => {
1122+
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
1123+
// that of their type parameters. Note: we don't include `HashSet` and `HashMap`
1124+
// because they have no impl for `Hash` or `Ord`.
1125+
let def_id = def.did();
1126+
let is_std_collection = [
1127+
sym::Option,
1128+
sym::Result,
1129+
sym::LinkedList,
1130+
sym::Vec,
1131+
sym::VecDeque,
1132+
sym::BTreeMap,
1133+
sym::BTreeSet,
1134+
sym::Rc,
1135+
sym::Arc,
1136+
]
1137+
.iter()
1138+
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id));
1139+
let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
1140+
if is_std_collection || is_box {
1141+
// The type is mutable if any of its type parameters are
1142+
substs.types().any(|ty| is_interior_mut_ty(cx, ty))
1143+
} else {
1144+
!ty.has_escaping_bound_vars()
1145+
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
1146+
&& !ty.is_freeze(cx.tcx, cx.param_env)
1147+
}
1148+
},
1149+
_ => false,
1150+
}
1151+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
ignore-interior-mutability = ["std::cell::Cell"]
1+
ignore-interior-mutability = ["std::cell::Cell"]

tests/ui-toml/ifs_same_cond/ifs_same_cond.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,13 @@ fn main() {}
66
fn issue10272() {
77
use std::cell::Cell;
88

9+
// Because the `ignore-interior-mutability` configuration
10+
// is set to ignore for `std::cell::Cell`, the following `get()` calls
11+
// should trigger warning
912
let x = Cell::new(true);
1013
if x.get() {
1114
} else if !x.take() {
1215
} else if x.get() {
13-
// ok, x is interior mutable type
14-
} else {
15-
}
16-
17-
let a = [Cell::new(true)];
18-
if a[0].get() {
19-
} else if a[0].take() {
20-
} else if a[0].get() {
21-
// ok, a contains interior mutable type
2216
} else {
2317
}
2418
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: this `if` has the same condition as a previous `if`
2+
--> $DIR/ifs_same_cond.rs:15:15
3+
|
4+
LL | } else if x.get() {
5+
| ^^^^^^^
6+
|
7+
note: same as this
8+
--> $DIR/ifs_same_cond.rs:13:8
9+
|
10+
LL | if x.get() {
11+
| ^^^^^^^
12+
= note: `-D clippy::ifs-same-cond` implied by `-D warnings`
13+
14+
error: aborting due to previous error
15+

tests/ui/ifs_same_cond.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ fn issue10272() {
5959
// ok, p is mutable pointer
6060
} else {
6161
}
62+
63+
let x = std::cell::Cell::new(true);
64+
if x.get() {
65+
} else if !x.take() {
66+
} else if x.get() {
67+
// ok, x is interior mutable type
68+
} else {
69+
}
6270
}
6371

6472
fn main() {}

0 commit comments

Comments
 (0)