@@ -2,18 +2,14 @@ use super::REDUNDANT_PATTERN_MATCHING;
2
2
use clippy_utils:: diagnostics:: span_lint_and_then;
3
3
use clippy_utils:: source:: snippet;
4
4
use clippy_utils:: sugg:: Sugg ;
5
- use clippy_utils:: ty:: { implements_trait , is_type_diagnostic_item , is_type_lang_item , match_type } ;
6
- use clippy_utils:: { higher , match_def_path } ;
7
- use clippy_utils:: { is_lang_ctor, is_trait_method, paths} ;
5
+ use clippy_utils:: ty:: type_needs_ordered_drop ;
6
+ use clippy_utils:: visitors :: any_temporaries_need_ordered_drop ;
7
+ use clippy_utils:: { higher , is_lang_ctor, is_trait_method, match_def_path , paths} ;
8
8
use if_chain:: if_chain;
9
9
use rustc_ast:: ast:: LitKind ;
10
- use rustc_data_structures:: fx:: FxHashSet ;
11
10
use rustc_errors:: Applicability ;
12
11
use rustc_hir:: LangItem :: { OptionNone , PollPending } ;
13
- use rustc_hir:: {
14
- intravisit:: { walk_expr, Visitor } ,
15
- Arm , Block , Expr , ExprKind , LangItem , Node , Pat , PatKind , QPath , UnOp ,
16
- } ;
12
+ use rustc_hir:: { Arm , Expr , ExprKind , Node , Pat , PatKind , QPath , UnOp } ;
17
13
use rustc_lint:: LateContext ;
18
14
use rustc_middle:: ty:: { self , subst:: GenericArgKind , DefIdTree , Ty } ;
19
15
use rustc_span:: sym;
@@ -32,59 +28,6 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
32
28
}
33
29
}
34
30
35
- /// Checks if the drop order for a type matters. Some std types implement drop solely to
36
- /// deallocate memory. For these types, and composites containing them, changing the drop order
37
- /// won't result in any observable side effects.
38
- fn type_needs_ordered_drop < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
39
- type_needs_ordered_drop_inner ( cx, ty, & mut FxHashSet :: default ( ) )
40
- }
41
-
42
- fn type_needs_ordered_drop_inner < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , seen : & mut FxHashSet < Ty < ' tcx > > ) -> bool {
43
- if !seen. insert ( ty) {
44
- return false ;
45
- }
46
- if !ty. needs_drop ( cx. tcx , cx. param_env ) {
47
- false
48
- } else if !cx
49
- . tcx
50
- . lang_items ( )
51
- . drop_trait ( )
52
- . map_or ( false , |id| implements_trait ( cx, ty, id, & [ ] ) )
53
- {
54
- // This type doesn't implement drop, so no side effects here.
55
- // Check if any component type has any.
56
- match ty. kind ( ) {
57
- ty:: Tuple ( fields) => fields. iter ( ) . any ( |ty| type_needs_ordered_drop_inner ( cx, ty, seen) ) ,
58
- ty:: Array ( ty, _) => type_needs_ordered_drop_inner ( cx, * ty, seen) ,
59
- ty:: Adt ( adt, subs) => adt
60
- . all_fields ( )
61
- . map ( |f| f. ty ( cx. tcx , subs) )
62
- . any ( |ty| type_needs_ordered_drop_inner ( cx, ty, seen) ) ,
63
- _ => true ,
64
- }
65
- }
66
- // Check for std types which implement drop, but only for memory allocation.
67
- else if is_type_diagnostic_item ( cx, ty, sym:: Vec )
68
- || is_type_lang_item ( cx, ty, LangItem :: OwnedBox )
69
- || is_type_diagnostic_item ( cx, ty, sym:: Rc )
70
- || is_type_diagnostic_item ( cx, ty, sym:: Arc )
71
- || is_type_diagnostic_item ( cx, ty, sym:: cstring_type)
72
- || is_type_diagnostic_item ( cx, ty, sym:: BTreeMap )
73
- || is_type_diagnostic_item ( cx, ty, sym:: LinkedList )
74
- || match_type ( cx, ty, & paths:: WEAK_RC )
75
- || match_type ( cx, ty, & paths:: WEAK_ARC )
76
- {
77
- // Check all of the generic arguments.
78
- if let ty:: Adt ( _, subs) = ty. kind ( ) {
79
- subs. types ( ) . any ( |ty| type_needs_ordered_drop_inner ( cx, ty, seen) )
80
- } else {
81
- true
82
- }
83
- } else {
84
- true
85
- }
86
- }
87
-
88
31
// Extract the generic arguments out of a type
89
32
fn try_get_generic_ty ( ty : Ty < ' _ > , index : usize ) -> Option < Ty < ' _ > > {
90
33
if_chain ! {
@@ -99,79 +42,6 @@ fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
99
42
}
100
43
}
101
44
102
- // Checks if there are any temporaries created in the given expression for which drop order
103
- // matters.
104
- fn temporaries_need_ordered_drop < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) -> bool {
105
- struct V < ' a , ' tcx > {
106
- cx : & ' a LateContext < ' tcx > ,
107
- res : bool ,
108
- }
109
- impl < ' a , ' tcx > Visitor < ' tcx > for V < ' a , ' tcx > {
110
- fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
111
- match expr. kind {
112
- // Taking the reference of a value leaves a temporary
113
- // e.g. In `&String::new()` the string is a temporary value.
114
- // Remaining fields are temporary values
115
- // e.g. In `(String::new(), 0).1` the string is a temporary value.
116
- ExprKind :: AddrOf ( _, _, expr) | ExprKind :: Field ( expr, _) => {
117
- if !matches ! ( expr. kind, ExprKind :: Path ( _) ) {
118
- if type_needs_ordered_drop ( self . cx , self . cx . typeck_results ( ) . expr_ty ( expr) ) {
119
- self . res = true ;
120
- } else {
121
- self . visit_expr ( expr) ;
122
- }
123
- }
124
- } ,
125
- // the base type is alway taken by reference.
126
- // e.g. In `(vec![0])[0]` the vector is a temporary value.
127
- ExprKind :: Index ( base, index) => {
128
- if !matches ! ( base. kind, ExprKind :: Path ( _) ) {
129
- if type_needs_ordered_drop ( self . cx , self . cx . typeck_results ( ) . expr_ty ( base) ) {
130
- self . res = true ;
131
- } else {
132
- self . visit_expr ( base) ;
133
- }
134
- }
135
- self . visit_expr ( index) ;
136
- } ,
137
- // Method calls can take self by reference.
138
- // e.g. In `String::new().len()` the string is a temporary value.
139
- ExprKind :: MethodCall ( _, [ self_arg, args @ ..] , _) => {
140
- if !matches ! ( self_arg. kind, ExprKind :: Path ( _) ) {
141
- let self_by_ref = self
142
- . cx
143
- . typeck_results ( )
144
- . type_dependent_def_id ( expr. hir_id )
145
- . map_or ( false , |id| self . cx . tcx . fn_sig ( id) . skip_binder ( ) . inputs ( ) [ 0 ] . is_ref ( ) ) ;
146
- if self_by_ref && type_needs_ordered_drop ( self . cx , self . cx . typeck_results ( ) . expr_ty ( self_arg) ) {
147
- self . res = true ;
148
- } else {
149
- self . visit_expr ( self_arg) ;
150
- }
151
- }
152
- args. iter ( ) . for_each ( |arg| self . visit_expr ( arg) ) ;
153
- } ,
154
- // Either explicitly drops values, or changes control flow.
155
- ExprKind :: DropTemps ( _)
156
- | ExprKind :: Ret ( _)
157
- | ExprKind :: Break ( ..)
158
- | ExprKind :: Yield ( ..)
159
- | ExprKind :: Block ( Block { expr : None , .. } , _)
160
- | ExprKind :: Loop ( ..) => ( ) ,
161
-
162
- // Only consider the final expression.
163
- ExprKind :: Block ( Block { expr : Some ( expr) , .. } , _) => self . visit_expr ( expr) ,
164
-
165
- _ => walk_expr ( self , expr) ,
166
- }
167
- }
168
- }
169
-
170
- let mut v = V { cx, res : false } ;
171
- v. visit_expr ( expr) ;
172
- v. res
173
- }
174
-
175
45
fn find_sugg_for_if_let < ' tcx > (
176
46
cx : & LateContext < ' tcx > ,
177
47
expr : & ' tcx Expr < ' _ > ,
@@ -243,7 +113,7 @@ fn find_sugg_for_if_let<'tcx>(
243
113
// scrutinee would be, so they have to be considered as well.
244
114
// e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
245
115
// for the duration if body.
246
- let needs_drop = type_needs_ordered_drop ( cx, check_ty) || temporaries_need_ordered_drop ( cx, let_expr) ;
116
+ let needs_drop = type_needs_ordered_drop ( cx, check_ty) || any_temporaries_need_ordered_drop ( cx, let_expr) ;
247
117
248
118
// check that `while_let_on_iterator` lint does not trigger
249
119
if_chain ! {
0 commit comments