1
1
use clippy_utils:: diagnostics:: { span_lint_and_note, span_lint_and_then} ;
2
2
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} ;
4
4
use clippy_utils:: visitors:: for_each_expr;
5
5
use clippy_utils:: {
6
6
capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt,
7
7
if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName , HirEqInterExpr , SpanlessEq ,
8
8
} ;
9
9
use core:: iter;
10
10
use core:: ops:: ControlFlow ;
11
- use rustc_data_structures:: fx:: FxHashSet ;
12
11
use rustc_errors:: Applicability ;
13
- use rustc_hir:: def_id:: DefId ;
12
+ use rustc_hir:: def_id:: DefIdSet ;
14
13
use rustc_hir:: intravisit;
15
14
use rustc_hir:: { BinOpKind , Block , Expr , ExprKind , HirId , HirIdSet , Stmt , StmtKind } ;
16
15
use rustc_lint:: { LateContext , LateLintPass } ;
@@ -164,12 +163,14 @@ declare_clippy_lint! {
164
163
165
164
pub struct CopyAndPaste {
166
165
ignore_interior_mutability : Vec < String > ,
166
+ ignored_ty_ids : DefIdSet ,
167
167
}
168
168
169
169
impl CopyAndPaste {
170
170
pub fn new ( ignore_interior_mutability : Vec < String > ) -> Self {
171
171
Self {
172
172
ignore_interior_mutability,
173
+ ignored_ty_ids : DefIdSet :: new ( ) ,
173
174
}
174
175
}
175
176
}
@@ -182,17 +183,18 @@ impl_lint_pass!(CopyAndPaste => [
182
183
] ) ;
183
184
184
185
impl < ' 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
+ }
185
194
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
186
195
if !expr. span . from_expansion ( ) && matches ! ( expr. kind, ExprKind :: If ( ..) ) && !is_else_clause ( cx. tcx , expr) {
187
196
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 ) ;
196
198
lint_same_fns_in_if_cond ( cx, & conds) ;
197
199
let all_same =
198
200
!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
569
571
} )
570
572
}
571
573
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 {
577
575
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) ) ;
583
579
584
- if is_ignored_ty
580
+ is_inner_mut_ty
585
581
|| caller_ty. is_mutable_ptr ( )
582
+ // `find_binding_init` will return the binding iff its not mutable
586
583
|| path_to_local ( caller_expr)
587
584
. and_then ( |hid| find_binding_init ( cx, hid) )
588
585
. is_none ( )
589
- {
590
- return true ;
591
- }
592
-
593
- false
594
586
}
595
587
596
588
/// 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 ) {
598
590
for ( i, j) in search_same (
599
591
conds,
600
592
|e| hash_expr ( cx, e) ,
601
593
|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.
602
596
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) {
604
598
false
605
599
} else {
606
600
SpanlessEq :: new ( cx) . eq_expr ( lhs, rhs)
0 commit comments