@@ -1367,28 +1367,38 @@ fn check_unsafe_block(cx: &Context, e: &ast::Expr) {
13671367 }
13681368}
13691369
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+ }
13891392 }
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" ) ;
13901401 }
1391- _ => ( )
13921402 }
13931403}
13941404
@@ -1684,7 +1694,6 @@ impl<'a> Visitor<()> for Context<'a> {
16841694 fn visit_pat ( & mut self , p : & ast:: Pat , _: ( ) ) {
16851695 check_pat_non_uppercase_statics ( self , p) ;
16861696 check_pat_uppercase_variable ( self , p) ;
1687- check_unused_mut_pat ( self , p) ;
16881697
16891698 visit:: walk_pat ( self , p, ( ) ) ;
16901699 }
@@ -1700,6 +1709,11 @@ impl<'a> Visitor<()> for Context<'a> {
17001709 ast:: ExprParen ( expr) => if self . negated_expr_id == e. id {
17011710 self . negated_expr_id = expr. id
17021711 } ,
1712+ ast:: ExprMatch ( _, ref arms) => {
1713+ for a in arms. iter ( ) {
1714+ check_unused_mut_pat ( self , a. pats . as_slice ( ) ) ;
1715+ }
1716+ } ,
17031717 _ => ( )
17041718 } ;
17051719
@@ -1723,6 +1737,18 @@ impl<'a> Visitor<()> for Context<'a> {
17231737 check_unused_result ( self , s) ;
17241738 check_unnecessary_parens_stmt ( self , s) ;
17251739
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+
17261752 visit:: walk_stmt ( self , s, ( ) ) ;
17271753 }
17281754
@@ -1732,6 +1758,10 @@ impl<'a> Visitor<()> for Context<'a> {
17321758 visit:: walk_fn ( this, fk, decl, body, span, id, ( ) ) ;
17331759 } ;
17341760
1761+ for a in decl. inputs . iter ( ) {
1762+ check_unused_mut_pat ( self , & [ a. pat ] ) ;
1763+ }
1764+
17351765 match * fk {
17361766 visit:: FkMethod ( _, _, m) => {
17371767 self . with_lint_attrs ( m. attrs . as_slice ( ) , |cx| {
0 commit comments