1
1
use crate :: utils:: { get_parent_node, in_macro, is_allowed, peel_mid_ty_refs, snippet_with_context, span_lint_and_sugg} ;
2
2
use rustc_ast:: util:: parser:: PREC_PREFIX ;
3
3
use rustc_errors:: Applicability ;
4
- use rustc_hir:: { BorrowKind , Destination , Expr , ExprKind , HirId , MatchSource , Mutability , Node , UnOp } ;
4
+ use rustc_hir:: { BorrowKind , Expr , ExprKind , HirId , MatchSource , Mutability , Node , UnOp } ;
5
5
use rustc_lint:: { LateContext , LateLintPass } ;
6
- use rustc_middle:: ty:: { self , adjustment :: Adjustment , Ty , TyCtxt , TyS , TypeckResults } ;
6
+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TyS , TypeckResults } ;
7
7
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
8
8
use rustc_span:: { symbol:: sym, Span } ;
9
9
@@ -66,7 +66,7 @@ enum State {
66
66
67
67
// A reference operation considered by this lint pass
68
68
enum RefOp {
69
- Method ,
69
+ Method ( Mutability ) ,
70
70
Deref ,
71
71
AddrOf ,
72
72
}
@@ -100,18 +100,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
100
100
match ( self . state . take ( ) , kind) {
101
101
( None , kind) => {
102
102
let parent = get_parent_node ( cx. tcx , expr. hir_id ) ;
103
-
104
- let expr_adjustments = find_adjustments ( cx. tcx , typeck, expr) ;
105
103
let expr_ty = typeck. expr_ty ( expr) ;
106
- let target_mut =
107
- if let ty:: Ref ( _, _, mutability) = * expr_adjustments. last ( ) . map_or ( expr_ty, |a| a. target ) . kind ( ) {
108
- mutability
109
- } else {
110
- Mutability :: Not
111
- } ;
112
104
113
105
match kind {
114
- RefOp :: Method
106
+ RefOp :: Method ( target_mut )
115
107
if !is_allowed ( cx, EXPLICIT_DEREF_METHODS , expr. hir_id )
116
108
&& is_linted_explicit_deref_position ( parent, expr. hir_id ) =>
117
109
{
@@ -133,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
133
125
_ => ( ) ,
134
126
}
135
127
} ,
136
- ( Some ( ( State :: DerefMethod { ty_changed_count, .. } , data) ) , RefOp :: Method ) => {
128
+ ( Some ( ( State :: DerefMethod { ty_changed_count, .. } , data) ) , RefOp :: Method ( _ ) ) => {
137
129
self . state = Some ( (
138
130
State :: DerefMethod {
139
131
ty_changed_count : if deref_method_same_type ( typeck. expr_ty ( expr) , typeck. expr_ty ( sub_expr) ) {
@@ -173,9 +165,13 @@ fn try_parse_ref_op(
173
165
ExprKind :: AddrOf ( BorrowKind :: Ref , _, sub_expr) => return Some ( ( RefOp :: AddrOf , sub_expr) ) ,
174
166
_ => return None ,
175
167
} ;
176
- ( tcx. is_diagnostic_item ( sym:: deref_method, def_id)
177
- || tcx. trait_of_item ( def_id) ? == tcx. lang_items ( ) . deref_mut_trait ( ) ?)
178
- . then ( || ( RefOp :: Method , arg) )
168
+ if tcx. is_diagnostic_item ( sym:: deref_method, def_id) {
169
+ Some ( ( RefOp :: Method ( Mutability :: Not ) , arg) )
170
+ } else if tcx. trait_of_item ( def_id) ? == tcx. lang_items ( ) . deref_mut_trait ( ) ? {
171
+ Some ( ( RefOp :: Method ( Mutability :: Mut ) , arg) )
172
+ } else {
173
+ None
174
+ }
179
175
}
180
176
181
177
// Checks whether the type for a deref call actually changed the type, not just the mutability of
@@ -191,48 +187,6 @@ fn deref_method_same_type(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
191
187
}
192
188
}
193
189
194
- // Adjustments are sometimes made in the parent block rather than the expression itself.
195
- fn find_adjustments (
196
- tcx : TyCtxt < ' tcx > ,
197
- typeck : & ' tcx TypeckResults < ' _ > ,
198
- expr : & ' tcx Expr < ' _ > ,
199
- ) -> & ' tcx [ Adjustment < ' tcx > ] {
200
- let map = tcx. hir ( ) ;
201
- let mut iter = map. parent_iter ( expr. hir_id ) ;
202
- let mut prev = expr;
203
-
204
- loop {
205
- match typeck. expr_adjustments ( prev) {
206
- [ ] => ( ) ,
207
- a => break a,
208
- } ;
209
-
210
- match iter. next ( ) . map ( |( _, x) | x) {
211
- Some ( Node :: Block ( _) ) => {
212
- if let Some ( ( _, Node :: Expr ( e) ) ) = iter. next ( ) {
213
- prev = e;
214
- } else {
215
- // This shouldn't happen. Blocks are always contained in an expression.
216
- break & [ ] ;
217
- }
218
- } ,
219
- Some ( Node :: Expr ( & Expr {
220
- kind : ExprKind :: Break ( Destination { target_id : Ok ( id) , .. } , _) ,
221
- ..
222
- } ) ) => {
223
- if let Some ( Node :: Expr ( e) ) = map. find ( id) {
224
- prev = e;
225
- iter = map. parent_iter ( id) ;
226
- continue ;
227
- }
228
- // This shouldn't happen. The destination should definitely exist at this point.
229
- break & [ ] ;
230
- } ,
231
- _ => break & [ ] ,
232
- }
233
- }
234
- }
235
-
236
190
// Checks whether the parent node is a suitable context for switching from a deref method to the
237
191
// deref operator.
238
192
fn is_linted_explicit_deref_position ( parent : Option < Node < ' _ > > , child_id : HirId ) -> bool {
@@ -331,7 +285,10 @@ fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: Stat
331
285
cx,
332
286
EXPLICIT_DEREF_METHODS ,
333
287
data. span ,
334
- "explicit `deref` method call" ,
288
+ match data. target_mut {
289
+ Mutability :: Not => "explicit `deref` method call" ,
290
+ Mutability :: Mut => "explicit `deref_mut` method call" ,
291
+ } ,
335
292
"try this" ,
336
293
format ! ( "{}{}{}" , addr_of_str, deref_str, expr_str) ,
337
294
app,
0 commit comments