@@ -3,16 +3,19 @@ use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, sn
33use clippy_utils:: ty:: needs_ordered_drop;
44use clippy_utils:: visitors:: for_each_expr;
55use 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} ;
99use core:: iter;
1010use core:: ops:: ControlFlow ;
11+ use rustc_data_structures:: fx:: FxHashSet ;
1112use rustc_errors:: Applicability ;
13+ use rustc_hir:: def_id:: DefId ;
1214use rustc_hir:: intravisit;
1315use rustc_hir:: { BinOpKind , Block , Expr , ExprKind , HirId , HirIdSet , Stmt , StmtKind } ;
1416use 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} ;
1619use rustc_span:: hygiene:: walk_chain;
1720use rustc_span:: source_map:: SourceMap ;
1821use 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)
0 commit comments