11use clippy_utils:: diagnostics:: { span_lint_and_note, span_lint_and_then} ;
22use 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} ;
44use clippy_utils:: visitors:: for_each_expr;
55use clippy_utils:: {
66 capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt,
77 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 ;
1211use rustc_errors:: Applicability ;
13- use rustc_hir:: def_id:: DefId ;
12+ use rustc_hir:: def_id:: DefIdSet ;
1413use rustc_hir:: intravisit;
1514use rustc_hir:: { BinOpKind , Block , Expr , ExprKind , HirId , HirIdSet , Stmt , StmtKind } ;
1615use rustc_lint:: { LateContext , LateLintPass } ;
@@ -164,12 +163,14 @@ declare_clippy_lint! {
164163
165164pub struct CopyAndPaste {
166165 ignore_interior_mutability : Vec < String > ,
166+ ignored_ty_ids : DefIdSet ,
167167}
168168
169169impl CopyAndPaste {
170170 pub fn new ( ignore_interior_mutability : Vec < String > ) -> Self {
171171 Self {
172172 ignore_interior_mutability,
173+ ignored_ty_ids : DefIdSet :: new ( ) ,
173174 }
174175 }
175176}
@@ -182,17 +183,18 @@ impl_lint_pass!(CopyAndPaste => [
182183] ) ;
183184
184185impl < ' tcx > LateLintPass < ' tcx > for CopyAndPaste {
186+ fn check_crate ( & mut self , cx : & LateContext < ' tcx > ) {
187+ for ignored_ty in & self . ignore_interior_mutability {
188+ let path: Vec < & str > = ignored_ty. split ( "::" ) . collect ( ) ;
189+ for id in def_path_def_ids ( cx, path. as_slice ( ) ) {
190+ self . ignored_ty_ids . insert ( id) ;
191+ }
192+ }
193+ }
185194 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
186195 if !expr. span . from_expansion ( ) && matches ! ( expr. kind, ExprKind :: If ( ..) ) && !is_else_clause ( cx. tcx , expr) {
187196 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) ;
197+ lint_same_cond ( cx, & conds, & self . ignored_ty_ids ) ;
196198 lint_same_fns_in_if_cond ( cx, & conds) ;
197199 let all_same =
198200 !is_lint_allowed ( cx, IF_SAME_THEN_ELSE , expr. hir_id ) && lint_if_same_then_else ( cx, & conds, & blocks) ;
@@ -569,38 +571,30 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
569571 } )
570572}
571573
572- fn method_caller_is_ignored_or_mutable (
573- cx : & LateContext < ' _ > ,
574- caller_expr : & Expr < ' _ > ,
575- ignored_ty_ids : & FxHashSet < DefId > ,
576- ) -> bool {
574+ fn method_caller_is_mutable ( cx : & LateContext < ' _ > , caller_expr : & Expr < ' _ > , ignored_ty_ids : & DefIdSet ) -> bool {
577575 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- } ;
576+ // Check if given type has inner mutability and was not set to ignored by the configuration
577+ let is_inner_mut_ty = is_interior_mut_ty ( cx, caller_ty)
578+ && !matches ! ( caller_ty. ty_adt_id( ) , Some ( adt_id) if ignored_ty_ids. contains( & adt_id) ) ;
583579
584- if is_ignored_ty
580+ is_inner_mut_ty
585581 || caller_ty. is_mutable_ptr ( )
582+ // `find_binding_init` will return the binding iff its not mutable
586583 || path_to_local ( caller_expr)
587584 . and_then ( |hid| find_binding_init ( cx, hid) )
588585 . is_none ( )
589- {
590- return true ;
591- }
592-
593- false
594586}
595587
596588/// Implementation of `IFS_SAME_COND`.
597- fn lint_same_cond ( cx : & LateContext < ' _ > , conds : & [ & Expr < ' _ > ] , ignored_ty_ids : & FxHashSet < DefId > ) {
589+ fn lint_same_cond ( cx : & LateContext < ' _ > , conds : & [ & Expr < ' _ > ] , ignored_ty_ids : & DefIdSet ) {
598590 for ( i, j) in search_same (
599591 conds,
600592 |e| hash_expr ( cx, e) ,
601593 |lhs, rhs| {
594+ // Ignore eq_expr side effects iff one of the expressin kind is a method call
595+ // and the caller is not a mutable, including inner mutable type.
602596 if let ExprKind :: MethodCall ( _, caller, _, _) = lhs. kind {
603- if method_caller_is_ignored_or_mutable ( cx, caller, ignored_ty_ids) {
597+ if method_caller_is_mutable ( cx, caller, ignored_ty_ids) {
604598 false
605599 } else {
606600 SpanlessEq :: new ( cx) . eq_expr ( lhs, rhs)
0 commit comments