@@ -105,7 +105,7 @@ use lint;
105
105
use errors:: Applicability ;
106
106
use util:: nodemap:: { NodeMap , HirIdMap , HirIdSet } ;
107
107
108
- use std:: collections:: VecDeque ;
108
+ use std:: collections:: { BTreeMap , VecDeque } ;
109
109
use std:: { fmt, u32} ;
110
110
use std:: io:: prelude:: * ;
111
111
use std:: io;
@@ -1446,7 +1446,7 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local)
1446
1446
None => {
1447
1447
this. pat_bindings ( & local. pat , |this, ln, var, sp, id| {
1448
1448
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) ;
1450
1450
} )
1451
1451
}
1452
1452
}
@@ -1455,12 +1455,29 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local)
1455
1455
}
1456
1456
1457
1457
fn 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
+
1464
1481
intravisit:: walk_arm ( this, arm) ;
1465
1482
}
1466
1483
@@ -1551,7 +1568,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
1551
1568
let var = self . variable ( hir_id, sp) ;
1552
1569
// Ignore unused self.
1553
1570
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) {
1555
1572
if self . live_on_entry ( entry_ln, var) . is_none ( ) {
1556
1573
self . report_dead_assign ( hir_id, sp, var, true ) ;
1557
1574
}
@@ -1563,14 +1580,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
1563
1580
1564
1581
fn warn_about_unused_or_dead_vars_in_pat ( & mut self , pat : & hir:: Pat ) {
1565
1582
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) {
1567
1584
this. warn_about_dead_assign ( sp, id, ln, var) ;
1568
1585
}
1569
1586
} )
1570
1587
}
1571
1588
1572
1589
fn warn_about_unused ( & self ,
1573
- sp : Span ,
1590
+ spans : Vec < Span > ,
1574
1591
hir_id : HirId ,
1575
1592
ln : LiveNode ,
1576
1593
var : Variable )
@@ -1587,33 +1604,36 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
1587
1604
self . assigned_on_exit ( ln, var) . is_some ( )
1588
1605
} ;
1589
1606
1590
- let suggest_underscore_msg = format ! ( "consider using `_{}` instead" , name) ;
1591
-
1592
1607
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
+ ) ;
1598
1615
} 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
+
1602
1623
if self . ir . variable_is_shorthand ( var) {
1603
- err. span_suggestion (
1604
- sp,
1624
+ err. multipart_suggestion (
1605
1625
"try ignoring the field" ,
1606
- format ! ( "{}: _" , name) ,
1607
- Applicability :: MachineApplicable ,
1626
+ spans . iter ( ) . map ( |span| ( * span , format ! ( "{}: _" , name) ) ) . collect ( ) ,
1627
+ Applicability :: MachineApplicable
1608
1628
) ;
1609
1629
} 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 ( ) ,
1614
1633
Applicability :: MachineApplicable ,
1615
1634
) ;
1616
1635
}
1636
+
1617
1637
err. emit ( )
1618
1638
}
1619
1639
}
@@ -1623,11 +1643,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
1623
1643
}
1624
1644
}
1625
1645
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 ) {
1631
1647
if self . live_on_exit ( ln, var) . is_none ( ) {
1632
1648
self . report_dead_assign ( hir_id, sp, var, false ) ;
1633
1649
}
0 commit comments