@@ -1367,28 +1367,38 @@ fn check_unsafe_block(cx: &Context, e: &ast::Expr) {
1367
1367
}
1368
1368
}
1369
1369
1370
- fn check_unused_mut_pat ( cx : & Context , p : & ast:: Pat ) {
1371
- match p. node {
1372
- ast:: PatIdent ( ast:: BindByValue ( ast:: MutMutable ) ,
1373
- ref path, _) if pat_util:: pat_is_binding ( & cx. tcx . def_map , p) => {
1374
- // `let mut _a = 1;` doesn't need a warning.
1375
- let initial_underscore = if path. segments . len ( ) == 1 {
1376
- token:: get_ident ( path. segments
1377
- . get ( 0 )
1378
- . identifier ) . get ( ) . starts_with ( "_" )
1379
- } else {
1380
- cx. tcx . sess . span_bug ( p. span ,
1381
- "mutable binding that doesn't consist \
1382
- of exactly one segment")
1383
- } ;
1384
-
1385
- if !initial_underscore &&
1386
- !cx. tcx . used_mut_nodes . borrow ( ) . contains ( & p. id ) {
1387
- cx. span_lint ( UnusedMut , p. span ,
1388
- "variable does not need to be mutable" ) ;
1370
+ fn check_unused_mut_pat ( cx : & Context , pats : & [ @ast:: Pat ] ) {
1371
+ // collect all mutable pattern and group their NodeIDs by their Identifier to
1372
+ // avoid false warnings in match arms with multiple patterns
1373
+ let mut mutables = HashMap :: new ( ) ;
1374
+ for & p in pats. iter ( ) {
1375
+ pat_util:: pat_bindings ( & cx. tcx . def_map , p, |mode, id, _, path| {
1376
+ match mode {
1377
+ ast:: BindByValue ( ast:: MutMutable ) => {
1378
+ if path. segments . len ( ) != 1 {
1379
+ cx. tcx . sess . span_bug ( p. span ,
1380
+ "mutable binding that doesn't consist \
1381
+ of exactly one segment") ;
1382
+ }
1383
+ let ident = path. segments . get ( 0 ) . identifier ;
1384
+ if !token:: get_ident ( ident) . get ( ) . starts_with ( "_" ) {
1385
+ mutables. insert_or_update_with ( ident. name as uint , vec ! ( id) , |_, old| {
1386
+ old. push ( id) ;
1387
+ } ) ;
1388
+ }
1389
+ }
1390
+ _ => {
1391
+ }
1389
1392
}
1393
+ } ) ;
1394
+ }
1395
+
1396
+ let used_mutables = cx. tcx . used_mut_nodes . borrow ( ) ;
1397
+ for ( _, v) in mutables. iter ( ) {
1398
+ if !v. iter ( ) . any ( |e| used_mutables. contains ( e) ) {
1399
+ cx. span_lint ( UnusedMut , cx. tcx . map . span ( * v. get ( 0 ) ) ,
1400
+ "variable does not need to be mutable" ) ;
1390
1401
}
1391
- _ => ( )
1392
1402
}
1393
1403
}
1394
1404
@@ -1684,7 +1694,6 @@ impl<'a> Visitor<()> for Context<'a> {
1684
1694
fn visit_pat ( & mut self , p : & ast:: Pat , _: ( ) ) {
1685
1695
check_pat_non_uppercase_statics ( self , p) ;
1686
1696
check_pat_uppercase_variable ( self , p) ;
1687
- check_unused_mut_pat ( self , p) ;
1688
1697
1689
1698
visit:: walk_pat ( self , p, ( ) ) ;
1690
1699
}
@@ -1700,6 +1709,11 @@ impl<'a> Visitor<()> for Context<'a> {
1700
1709
ast:: ExprParen ( expr) => if self . negated_expr_id == e. id {
1701
1710
self . negated_expr_id = expr. id
1702
1711
} ,
1712
+ ast:: ExprMatch ( _, ref arms) => {
1713
+ for a in arms. iter ( ) {
1714
+ check_unused_mut_pat ( self , a. pats . as_slice ( ) ) ;
1715
+ }
1716
+ } ,
1703
1717
_ => ( )
1704
1718
} ;
1705
1719
@@ -1723,6 +1737,18 @@ impl<'a> Visitor<()> for Context<'a> {
1723
1737
check_unused_result ( self , s) ;
1724
1738
check_unnecessary_parens_stmt ( self , s) ;
1725
1739
1740
+ match s. node {
1741
+ ast:: StmtDecl ( d, _) => {
1742
+ match d. node {
1743
+ ast:: DeclLocal ( l) => {
1744
+ check_unused_mut_pat ( self , & [ l. pat ] ) ;
1745
+ } ,
1746
+ _ => { }
1747
+ }
1748
+ } ,
1749
+ _ => { }
1750
+ }
1751
+
1726
1752
visit:: walk_stmt ( self , s, ( ) ) ;
1727
1753
}
1728
1754
@@ -1732,6 +1758,10 @@ impl<'a> Visitor<()> for Context<'a> {
1732
1758
visit:: walk_fn ( this, fk, decl, body, span, id, ( ) ) ;
1733
1759
} ;
1734
1760
1761
+ for a in decl. inputs . iter ( ) {
1762
+ check_unused_mut_pat ( self , & [ a. pat ] ) ;
1763
+ }
1764
+
1735
1765
match * fk {
1736
1766
visit:: FkMethod ( _, _, m) => {
1737
1767
self . with_lint_attrs ( m. attrs . as_slice ( ) , |cx| {
0 commit comments