@@ -104,6 +104,7 @@ use ty::query::{Providers, queries};
104104use lint;
105105use errors:: Applicability ;
106106use util:: nodemap:: { NodeMap , HirIdMap , HirIdSet } ;
107+ use rustc_data_structures:: fx:: FxHashMap ;
107108
108109use std:: collections:: VecDeque ;
109110use std:: { fmt, u32} ;
@@ -1446,7 +1447,7 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local)
14461447 None => {
14471448 this. pat_bindings ( & local. pat , |this, ln, var, sp, id| {
14481449 let span = local. pat . simple_ident ( ) . map_or ( sp, |ident| ident. span ) ;
1449- this. warn_about_unused ( span, id, ln, var) ;
1450+ this. warn_about_unused ( vec ! [ span] , id, ln, var) ;
14501451 } )
14511452 }
14521453 }
@@ -1455,12 +1456,29 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local)
14551456}
14561457
14571458fn check_arm < ' a , ' tcx > ( this : & mut Liveness < ' a , ' tcx > , arm : & ' tcx hir:: Arm ) {
1458- // only consider the first pattern; any later patterns must have
1459- // the same bindings, and we also consider the first pattern to be
1460- // the "authoritative" set of ids
1461- this. arm_pats_bindings ( arm. pats . first ( ) . map ( |p| & * * p) , |this, ln, var, sp, id| {
1462- this. warn_about_unused ( sp, id, ln, var) ;
1463- } ) ;
1459+ // Only consider the variable from the first pattern; any later patterns must have
1460+ // the same bindings, and we also consider the first pattern to be the "authoritative" set of
1461+ // ids. However, we should take the spans of variables with the same name from the later
1462+ // patterns so the suggestions to prefix with underscores will apply to those too.
1463+ let mut vars: FxHashMap < String , ( LiveNode , Variable , HirId , Vec < Span > ) > = Default :: default ( ) ;
1464+
1465+ for pat in & arm. pats {
1466+ this. arm_pats_bindings ( Some ( & * pat) , |this, ln, var, sp, id| {
1467+ let name = this. ir . variable_name ( var) ;
1468+ vars. entry ( name)
1469+ . and_modify ( |( .., spans) | {
1470+ spans. push ( sp) ;
1471+ } )
1472+ . or_insert_with ( || {
1473+ ( ln, var, id, vec ! [ sp] )
1474+ } ) ;
1475+ } ) ;
1476+ }
1477+
1478+ for ( _, ( ln, var, id, spans) ) in vars {
1479+ this. warn_about_unused ( spans, id, ln, var) ;
1480+ }
1481+
14641482 intravisit:: walk_arm ( this, arm) ;
14651483}
14661484
@@ -1551,7 +1569,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
15511569 let var = self . variable ( hir_id, sp) ;
15521570 // Ignore unused self.
15531571 if ident. name != keywords:: SelfLower . name ( ) {
1554- if !self . warn_about_unused ( sp , hir_id, entry_ln, var) {
1572+ if !self . warn_about_unused ( vec ! [ sp ] , hir_id, entry_ln, var) {
15551573 if self . live_on_entry ( entry_ln, var) . is_none ( ) {
15561574 self . report_dead_assign ( hir_id, sp, var, true ) ;
15571575 }
@@ -1563,14 +1581,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
15631581
15641582 fn warn_about_unused_or_dead_vars_in_pat ( & mut self , pat : & hir:: Pat ) {
15651583 self . pat_bindings ( pat, |this, ln, var, sp, id| {
1566- if !this. warn_about_unused ( sp , id, ln, var) {
1584+ if !this. warn_about_unused ( vec ! [ sp ] , id, ln, var) {
15671585 this. warn_about_dead_assign ( sp, id, ln, var) ;
15681586 }
15691587 } )
15701588 }
15711589
15721590 fn warn_about_unused ( & self ,
1573- sp : Span ,
1591+ spans : Vec < Span > ,
15741592 hir_id : HirId ,
15751593 ln : LiveNode ,
15761594 var : Variable )
@@ -1587,29 +1605,36 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
15871605 self . assigned_on_exit ( ln, var) . is_some ( )
15881606 } ;
15891607
1590- let suggest_underscore_msg = format ! ( "consider using `_{}` instead" , name) ;
1591-
15921608 if is_assigned {
1593- self . ir . tcx
1594- . lint_hir_note ( lint:: builtin:: UNUSED_VARIABLES , hir_id, sp,
1595- & format ! ( "variable `{}` is assigned to, but never used" ,
1596- name) ,
1597- & suggest_underscore_msg) ;
1609+ self . ir . tcx . lint_hir_note (
1610+ lint:: builtin:: UNUSED_VARIABLES ,
1611+ hir_id,
1612+ spans. clone ( ) ,
1613+ & format ! ( "variable `{}` is assigned to, but never used" , name) ,
1614+ & format ! ( "consider using `_{}` instead" , name) ,
1615+ ) ;
15981616 } else if name != "self" {
1599- let msg = format ! ( "unused variable: `{}`" , name) ;
1600- let mut err = self . ir . tcx
1601- . struct_span_lint_hir ( lint:: builtin:: UNUSED_VARIABLES , hir_id, sp, & msg) ;
1617+ let mut err = self . ir . tcx . struct_span_lint_hir (
1618+ lint:: builtin:: UNUSED_VARIABLES ,
1619+ hir_id,
1620+ spans. clone ( ) ,
1621+ & format ! ( "unused variable: `{}`" , name) ,
1622+ ) ;
1623+
16021624 if self . ir . variable_is_shorthand ( var) {
1603- err. span_suggestion_with_applicability ( sp, "try ignoring the field" ,
1604- format ! ( "{}: _" , name) ,
1605- Applicability :: MachineApplicable ) ;
1625+ err. multipart_suggestion_with_applicability (
1626+ "try ignoring the field" ,
1627+ spans. iter ( ) . map ( |span| ( * span, format ! ( "{}: _" , name) ) ) . collect ( ) ,
1628+ Applicability :: MachineApplicable
1629+ ) ;
16061630 } else {
1607- err. span_suggestion_short_with_applicability (
1608- sp , & suggest_underscore_msg ,
1609- format ! ( "_{}" , name) ,
1631+ err. multipart_suggestion_with_applicability (
1632+ "consider prefixing with an underscore" ,
1633+ spans . iter ( ) . map ( |span| ( * span , format ! ( "_{}" , name) ) ) . collect ( ) ,
16101634 Applicability :: MachineApplicable ,
16111635 ) ;
16121636 }
1637+
16131638 err. emit ( )
16141639 }
16151640 }
@@ -1619,11 +1644,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
16191644 }
16201645 }
16211646
1622- fn warn_about_dead_assign ( & self ,
1623- sp : Span ,
1624- hir_id : HirId ,
1625- ln : LiveNode ,
1626- var : Variable ) {
1647+ fn warn_about_dead_assign ( & self , sp : Span , hir_id : HirId , ln : LiveNode , var : Variable ) {
16271648 if self . live_on_exit ( ln, var) . is_none ( ) {
16281649 self . report_dead_assign ( hir_id, sp, var, false ) ;
16291650 }
0 commit comments