@@ -104,6 +104,7 @@ use ty::query::{Providers, queries};
104
104
use lint;
105
105
use errors:: Applicability ;
106
106
use util:: nodemap:: { NodeMap , HirIdMap , HirIdSet } ;
107
+ use rustc_data_structures:: fx:: FxHashMap ;
107
108
108
109
use std:: collections:: VecDeque ;
109
110
use std:: { fmt, u32} ;
@@ -1446,7 +1447,7 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local)
1446
1447
None => {
1447
1448
this. pat_bindings ( & local. pat , |this, ln, var, sp, id| {
1448
1449
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) ;
1450
1451
} )
1451
1452
}
1452
1453
}
@@ -1455,12 +1456,29 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local)
1455
1456
}
1456
1457
1457
1458
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
- } ) ;
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
+
1464
1482
intravisit:: walk_arm ( this, arm) ;
1465
1483
}
1466
1484
@@ -1551,7 +1569,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
1551
1569
let var = self . variable ( hir_id, sp) ;
1552
1570
// Ignore unused self.
1553
1571
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) {
1555
1573
if self . live_on_entry ( entry_ln, var) . is_none ( ) {
1556
1574
self . report_dead_assign ( hir_id, sp, var, true ) ;
1557
1575
}
@@ -1563,14 +1581,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
1563
1581
1564
1582
fn warn_about_unused_or_dead_vars_in_pat ( & mut self , pat : & hir:: Pat ) {
1565
1583
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) {
1567
1585
this. warn_about_dead_assign ( sp, id, ln, var) ;
1568
1586
}
1569
1587
} )
1570
1588
}
1571
1589
1572
1590
fn warn_about_unused ( & self ,
1573
- sp : Span ,
1591
+ spans : Vec < Span > ,
1574
1592
hir_id : HirId ,
1575
1593
ln : LiveNode ,
1576
1594
var : Variable )
@@ -1587,29 +1605,36 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
1587
1605
self . assigned_on_exit ( ln, var) . is_some ( )
1588
1606
} ;
1589
1607
1590
- let suggest_underscore_msg = format ! ( "consider using `_{}` instead" , name) ;
1591
-
1592
1608
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
+ ) ;
1598
1616
} 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
+
1602
1624
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
+ ) ;
1606
1630
} 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 ( ) ,
1610
1634
Applicability :: MachineApplicable ,
1611
1635
) ;
1612
1636
}
1637
+
1613
1638
err. emit ( )
1614
1639
}
1615
1640
}
@@ -1619,11 +1644,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
1619
1644
}
1620
1645
}
1621
1646
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 ) {
1627
1648
if self . live_on_exit ( ln, var) . is_none ( ) {
1628
1649
self . report_dead_assign ( hir_id, sp, var, false ) ;
1629
1650
}
0 commit comments