@@ -105,7 +105,7 @@ use lint;
105105use errors:: Applicability ;
106106use util:: nodemap:: { NodeMap , HirIdMap , HirIdSet } ;
107107
108- use std:: collections:: VecDeque ;
108+ use std:: collections:: { BTreeMap , VecDeque } ;
109109use std:: { fmt, u32} ;
110110use std:: io:: prelude:: * ;
111111use std:: io;
@@ -1446,7 +1446,7 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local)
14461446 None => {
14471447 this. pat_bindings ( & local. pat , |this, ln, var, sp, id| {
14481448 let span = local. pat . simple_ident ( ) . map_or ( sp, |ident| ident. span ) ;
1449- this. warn_about_unused ( span, id, ln, var) ;
1449+ this. warn_about_unused ( vec ! [ span] , id, ln, var) ;
14501450 } )
14511451 }
14521452 }
@@ -1455,12 +1455,29 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local)
14551455}
14561456
14571457fn 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- } ) ;
1458+ // Only consider the variable from the first pattern; any later patterns must have
1459+ // the same bindings, and we also consider the first pattern to be the "authoritative" set of
1460+ // ids. However, we should take the spans of variables with the same name from the later
1461+ // patterns so the suggestions to prefix with underscores will apply to those too.
1462+ let mut vars: BTreeMap < String , ( LiveNode , Variable , HirId , Vec < Span > ) > = Default :: default ( ) ;
1463+
1464+ for pat in & arm. pats {
1465+ this. arm_pats_bindings ( Some ( & * pat) , |this, ln, var, sp, id| {
1466+ let name = this. ir . variable_name ( var) ;
1467+ vars. entry ( name)
1468+ . and_modify ( |( .., spans) | {
1469+ spans. push ( sp) ;
1470+ } )
1471+ . or_insert_with ( || {
1472+ ( ln, var, id, vec ! [ sp] )
1473+ } ) ;
1474+ } ) ;
1475+ }
1476+
1477+ for ( _, ( ln, var, id, spans) ) in vars {
1478+ this. warn_about_unused ( spans, id, ln, var) ;
1479+ }
1480+
14641481 intravisit:: walk_arm ( this, arm) ;
14651482}
14661483
@@ -1551,7 +1568,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
15511568 let var = self . variable ( hir_id, sp) ;
15521569 // Ignore unused self.
15531570 if ident. name != keywords:: SelfLower . name ( ) {
1554- if !self . warn_about_unused ( sp , hir_id, entry_ln, var) {
1571+ if !self . warn_about_unused ( vec ! [ sp ] , hir_id, entry_ln, var) {
15551572 if self . live_on_entry ( entry_ln, var) . is_none ( ) {
15561573 self . report_dead_assign ( hir_id, sp, var, true ) ;
15571574 }
@@ -1563,14 +1580,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
15631580
15641581 fn warn_about_unused_or_dead_vars_in_pat ( & mut self , pat : & hir:: Pat ) {
15651582 self . pat_bindings ( pat, |this, ln, var, sp, id| {
1566- if !this. warn_about_unused ( sp , id, ln, var) {
1583+ if !this. warn_about_unused ( vec ! [ sp ] , id, ln, var) {
15671584 this. warn_about_dead_assign ( sp, id, ln, var) ;
15681585 }
15691586 } )
15701587 }
15711588
15721589 fn warn_about_unused ( & self ,
1573- sp : Span ,
1590+ spans : Vec < Span > ,
15741591 hir_id : HirId ,
15751592 ln : LiveNode ,
15761593 var : Variable )
@@ -1587,33 +1604,36 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
15871604 self . assigned_on_exit ( ln, var) . is_some ( )
15881605 } ;
15891606
1590- let suggest_underscore_msg = format ! ( "consider using `_{}` instead" , name) ;
1591-
15921607 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) ;
1608+ self . ir . tcx . lint_hir_note (
1609+ lint:: builtin:: UNUSED_VARIABLES ,
1610+ hir_id,
1611+ spans. clone ( ) ,
1612+ & format ! ( "variable `{}` is assigned to, but never used" , name) ,
1613+ & format ! ( "consider using `_{}` instead" , name) ,
1614+ ) ;
15981615 } 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) ;
1616+ let mut err = self . ir . tcx . struct_span_lint_hir (
1617+ lint:: builtin:: UNUSED_VARIABLES ,
1618+ hir_id,
1619+ spans. clone ( ) ,
1620+ & format ! ( "unused variable: `{}`" , name) ,
1621+ ) ;
1622+
16021623 if self . ir . variable_is_shorthand ( var) {
1603- err. span_suggestion (
1604- sp,
1624+ err. multipart_suggestion (
16051625 "try ignoring the field" ,
1606- format ! ( "{}: _" , name) ,
1607- Applicability :: MachineApplicable ,
1626+ spans . iter ( ) . map ( |span| ( * span , format ! ( "{}: _" , name) ) ) . collect ( ) ,
1627+ Applicability :: MachineApplicable
16081628 ) ;
16091629 } else {
1610- err. span_suggestion_short (
1611- sp,
1612- & suggest_underscore_msg,
1613- format ! ( "_{}" , name) ,
1630+ err. multipart_suggestion (
1631+ "consider prefixing with an underscore" ,
1632+ spans. iter ( ) . map ( |span| ( * span, format ! ( "_{}" , name) ) ) . collect ( ) ,
16141633 Applicability :: MachineApplicable ,
16151634 ) ;
16161635 }
1636+
16171637 err. emit ( )
16181638 }
16191639 }
@@ -1623,11 +1643,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
16231643 }
16241644 }
16251645
1626- fn warn_about_dead_assign ( & self ,
1627- sp : Span ,
1628- hir_id : HirId ,
1629- ln : LiveNode ,
1630- var : Variable ) {
1646+ fn warn_about_dead_assign ( & self , sp : Span , hir_id : HirId , ln : LiveNode , var : Variable ) {
16311647 if self . live_on_exit ( ln, var) . is_none ( ) {
16321648 self . report_dead_assign ( hir_id, sp, var, false ) ;
16331649 }
0 commit comments