Skip to content

Commit f0ae2b7

Browse files
committed
make [ifs_same_cond] use ignore_interior_mutablility configuration
1 parent 8a9492a commit f0ae2b7

File tree

6 files changed

+91
-17
lines changed

6 files changed

+91
-17
lines changed

clippy_lints/src/copies.rs

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@ use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, sn
33
use clippy_utils::ty::needs_ordered_drop;
44
use clippy_utils::visitors::for_each_expr;
55
use clippy_utils::{
6-
capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence,
7-
is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq,
6+
capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt,
7+
if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq,
88
};
99
use core::iter;
1010
use core::ops::ControlFlow;
11+
use rustc_data_structures::fx::FxHashSet;
1112
use rustc_errors::Applicability;
13+
use rustc_hir::def_id::DefId;
1214
use rustc_hir::intravisit;
1315
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
1416
use rustc_lint::{LateContext, LateLintPass};
15-
use rustc_session::{declare_lint_pass, declare_tool_lint};
17+
use rustc_middle::query::Key;
18+
use rustc_session::{declare_tool_lint, impl_lint_pass};
1619
use rustc_span::hygiene::walk_chain;
1720
use rustc_span::source_map::SourceMap;
1821
use rustc_span::{BytePos, Span, Symbol};
@@ -159,7 +162,19 @@ declare_clippy_lint! {
159162
"`if` statement with shared code in all blocks"
160163
}
161164

162-
declare_lint_pass!(CopyAndPaste => [
165+
pub struct CopyAndPaste {
166+
ignore_interior_mutability: Vec<String>,
167+
}
168+
169+
impl CopyAndPaste {
170+
pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
171+
Self {
172+
ignore_interior_mutability,
173+
}
174+
}
175+
}
176+
177+
impl_lint_pass!(CopyAndPaste => [
163178
IFS_SAME_COND,
164179
SAME_FUNCTIONS_IN_IF_CONDITION,
165180
IF_SAME_THEN_ELSE,
@@ -170,7 +185,14 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
170185
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
171186
if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) {
172187
let (conds, blocks) = if_sequence(expr);
173-
lint_same_cond(cx, &conds);
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);
174196
lint_same_fns_in_if_cond(cx, &conds);
175197
let all_same =
176198
!is_lint_allowed(cx, IF_SAME_THEN_ELSE, expr.hir_id) && lint_if_same_then_else(cx, &conds, &blocks);
@@ -547,23 +569,41 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
547569
})
548570
}
549571

572+
fn method_caller_is_ignored_or_mutable(
573+
cx: &LateContext<'_>,
574+
caller_expr: &Expr<'_>,
575+
ignored_ty_ids: &FxHashSet<DefId>,
576+
) -> bool {
577+
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+
};
583+
584+
if is_ignored_ty
585+
|| caller_ty.is_mutable_ptr()
586+
|| path_to_local(caller_expr)
587+
.and_then(|hid| find_binding_init(cx, hid))
588+
.is_none()
589+
{
590+
return true;
591+
}
592+
593+
false
594+
}
595+
550596
/// Implementation of `IFS_SAME_COND`.
551-
fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
597+
fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &FxHashSet<DefId>) {
552598
for (i, j) in search_same(
553599
conds,
554600
|e| hash_expr(cx, e),
555601
|lhs, rhs| {
556-
// If any side (ex. lhs) is a method call, and the caller is not mutable,
557-
// then we can ignore side effects?
558602
if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind {
559-
if path_to_local(caller)
560-
.and_then(|hir_id| find_binding_init(cx, hir_id))
561-
.is_some()
562-
{
563-
// caller is not declared as mutable
564-
SpanlessEq::new(cx).eq_expr(lhs, rhs)
565-
} else {
603+
if method_caller_is_ignored_or_mutable(cx, caller, ignored_ty_ids) {
566604
false
605+
} else {
606+
SpanlessEq::new(cx).eq_expr(lhs, rhs)
567607
}
568608
} else {
569609
eq_expr_value(cx, lhs, rhs)

clippy_lints/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
656656
store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
657657
store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
658658
store.register_late_pass(|_| Box::new(regex::Regex));
659-
store.register_late_pass(|_| Box::new(copies::CopyAndPaste));
659+
let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
660+
store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
660661
store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
661662
store.register_late_pass(|_| Box::new(format::UselessFormat));
662663
store.register_late_pass(|_| Box::new(swap::Swap));

clippy_lints/src/utils/conf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ define_Conf! {
437437
///
438438
/// The maximum size of the `Err`-variant in a `Result` returned from a function
439439
(large_error_threshold: u64 = 128),
440-
/// Lint: MUTABLE_KEY_TYPE.
440+
/// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND.
441441
///
442442
/// A list of paths to types that should be treated like `Arc`, i.e. ignored but
443443
/// for the generic parameters for determining interior mutability
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ignore-interior-mutability = ["std::cell::Cell"]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![warn(clippy::ifs_same_cond)]
2+
#![allow(clippy::if_same_then_else, clippy::comparison_chain)]
3+
4+
fn main() {}
5+
6+
fn issue10272() {
7+
use std::cell::Cell;
8+
9+
let x = Cell::new(true);
10+
if x.get() {
11+
} else if !x.take() {
12+
} 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
22+
} else {
23+
}
24+
}

tests/ui/ifs_same_cond.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ fn issue10272() {
5151
} else if a.contains("ha") {
5252
} else if a == "wow" {
5353
}
54+
55+
let p: *mut i8 = std::ptr::null_mut();
56+
if p.is_null() {
57+
} else if p.align_offset(0) == 0 {
58+
} else if p.is_null() {
59+
// ok, p is mutable pointer
60+
} else {
61+
}
5462
}
5563

5664
fn main() {}

0 commit comments

Comments
 (0)