1
+ use rustc:: hir;
2
+ use rustc:: hir:: intravisit;
1
3
use rustc:: lint:: * ;
2
4
use rustc:: ty:: { TypeAndMut , TyRef } ;
3
- use rustc:: hir:: * ;
4
- use utils:: { in_external_macro, span_lint} ;
5
+ use utils:: { in_external_macro, recover_for_loop, span_lint} ;
5
6
6
7
/// **What it does:** This lint checks for instances of `mut mut` references.
7
8
///
@@ -27,30 +28,56 @@ impl LintPass for MutMut {
27
28
}
28
29
29
30
impl LateLintPass for MutMut {
30
- fn check_expr ( & mut self , cx : & LateContext , expr : & Expr ) {
31
- if in_external_macro ( cx, expr. span ) {
31
+ fn check_block ( & mut self , cx : & LateContext , block : & hir:: Block ) {
32
+ intravisit:: walk_block ( & mut MutVisitor { cx : cx } , block) ;
33
+ }
34
+
35
+ fn check_ty ( & mut self , cx : & LateContext , ty : & hir:: Ty ) {
36
+ use rustc:: hir:: intravisit:: Visitor ;
37
+
38
+ MutVisitor { cx : cx } . visit_ty ( ty) ;
39
+ }
40
+ }
41
+
42
+ pub struct MutVisitor < ' a , ' tcx : ' a > {
43
+ cx : & ' a LateContext < ' a , ' tcx > ,
44
+ }
45
+
46
+ impl < ' a , ' tcx , ' v > intravisit:: Visitor < ' v > for MutVisitor < ' a , ' tcx > {
47
+ fn visit_expr ( & mut self , expr : & ' v hir:: Expr ) {
48
+ if in_external_macro ( self . cx , expr. span ) {
32
49
return ;
33
50
}
34
51
35
- if let ExprAddrOf ( MutMutable , ref e) = expr. node {
36
- if let ExprAddrOf ( MutMutable , _) = e. node {
37
- span_lint ( cx, MUT_MUT , expr. span , "generally you want to avoid `&mut &mut _` if possible" ) ;
38
- } else {
39
- if let TyRef ( _, TypeAndMut { mutbl : MutMutable , .. } ) = cx. tcx . expr_ty ( e) . sty {
40
- span_lint ( cx,
41
- MUT_MUT ,
42
- expr. span ,
43
- "this expression mutably borrows a mutable reference. Consider reborrowing" ) ;
44
- }
52
+ if let Some ( ( _, arg, body) ) = recover_for_loop ( expr) {
53
+ // A `for` loop lowers to:
54
+ // ```rust
55
+ // match ::std::iter::Iterator::next(&mut iter) {
56
+ // // ^^^^
57
+ // ```
58
+ // Let's ignore the generated code.
59
+ intravisit:: walk_expr ( self , arg) ;
60
+ intravisit:: walk_expr ( self , body) ;
61
+ } else if let hir:: ExprAddrOf ( hir:: MutMutable , ref e) = expr. node {
62
+ if let hir:: ExprAddrOf ( hir:: MutMutable , _) = e. node {
63
+ span_lint ( self . cx , MUT_MUT , expr. span , "generally you want to avoid `&mut &mut _` if possible" ) ;
64
+ } else if let TyRef ( _, TypeAndMut { mutbl : hir:: MutMutable , .. } ) = self . cx . tcx . expr_ty ( e) . sty {
65
+ span_lint ( self . cx ,
66
+ MUT_MUT ,
67
+ expr. span ,
68
+ "this expression mutably borrows a mutable reference. Consider reborrowing" ) ;
45
69
}
46
70
}
47
71
}
48
72
49
- fn check_ty ( & mut self , cx : & LateContext , ty : & Ty ) {
50
- if let TyRptr ( _, MutTy { ty : ref pty, mutbl : MutMutable } ) = ty. node {
51
- if let TyRptr ( _, MutTy { mutbl : MutMutable , .. } ) = pty. node {
52
- span_lint ( cx, MUT_MUT , ty. span , "generally you want to avoid `&mut &mut _` if possible" ) ;
73
+ fn visit_ty ( & mut self , ty : & hir :: Ty ) {
74
+ if let hir :: TyRptr ( _, hir :: MutTy { ty : ref pty, mutbl : hir :: MutMutable } ) = ty. node {
75
+ if let hir :: TyRptr ( _, hir :: MutTy { mutbl : hir :: MutMutable , .. } ) = pty. node {
76
+ span_lint ( self . cx , MUT_MUT , ty. span , "generally you want to avoid `&mut &mut _` if possible" ) ;
53
77
}
78
+
54
79
}
80
+
81
+ intravisit:: walk_ty ( self , ty) ;
55
82
}
56
83
}
0 commit comments