3
3
// from live codes are live, and everything else is dead.
4
4
5
5
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
6
+ use rustc_errors:: Applicability ;
6
7
use rustc_hir as hir;
7
8
use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
8
9
use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
@@ -15,7 +16,7 @@ use rustc_middle::middle::privacy;
15
16
use rustc_middle:: ty:: { self , DefIdTree , TyCtxt } ;
16
17
use rustc_session:: lint;
17
18
18
- use rustc_span:: symbol:: { sym, Symbol } ;
19
+ use rustc_span:: symbol:: { sym, Ident , Symbol } ;
19
20
20
21
// Any local node that may call something in its body block should be
21
22
// explored. For example, if it's a live Node::Item that is a
@@ -505,6 +506,13 @@ fn find_live<'tcx>(
505
506
symbol_visitor. live_symbols
506
507
}
507
508
509
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
510
+ enum ExtraNote {
511
+ /// Use this to provide some examples in the diagnostic of potential other purposes for a value
512
+ /// or field that is dead code
513
+ OtherPurposeExamples ,
514
+ }
515
+
508
516
struct DeadVisitor < ' tcx > {
509
517
tcx : TyCtxt < ' tcx > ,
510
518
live_symbols : FxHashSet < hir:: HirId > ,
@@ -570,14 +578,42 @@ impl DeadVisitor<'tcx> {
570
578
& mut self ,
571
579
id : hir:: HirId ,
572
580
span : rustc_span:: Span ,
573
- name : Symbol ,
581
+ name : Ident ,
574
582
participle : & str ,
583
+ extra_note : Option < ExtraNote > ,
575
584
) {
576
585
if !name. as_str ( ) . starts_with ( '_' ) {
577
586
self . tcx . struct_span_lint_hir ( lint:: builtin:: DEAD_CODE , id, span, |lint| {
578
587
let def_id = self . tcx . hir ( ) . local_def_id ( id) ;
579
588
let descr = self . tcx . def_kind ( def_id) . descr ( def_id. to_def_id ( ) ) ;
580
- lint. build ( & format ! ( "{} is never {}: `{}`" , descr, participle, name) ) . emit ( )
589
+
590
+ let prefixed = vec ! [ ( name. span, format!( "_{}" , name) ) ] ;
591
+
592
+ let mut diag =
593
+ lint. build ( & format ! ( "{} is never {}: `{}`" , descr, participle, name) ) ;
594
+
595
+ diag. multipart_suggestion (
596
+ "if this is intentional, prefix it with an underscore" ,
597
+ prefixed,
598
+ Applicability :: MachineApplicable ,
599
+ ) ;
600
+
601
+ let mut note = format ! (
602
+ "the leading underscore signals that this {} serves some other \
603
+ purpose even if it isn't used in a way that we can detect.",
604
+ descr,
605
+ ) ;
606
+ if matches ! ( extra_note, Some ( ExtraNote :: OtherPurposeExamples ) ) {
607
+ note += " (e.g. for its effect when dropped or in foreign code)" ;
608
+ }
609
+
610
+ diag. note ( & note) ;
611
+
612
+ // Force the note we added to the front, before any other subdiagnostics
613
+ // added in lint.build(...)
614
+ diag. children . rotate_right ( 1 ) ;
615
+
616
+ diag. emit ( )
581
617
} ) ;
582
618
}
583
619
}
@@ -623,7 +659,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
623
659
hir:: ItemKind :: Struct ( ..) => "constructed" , // Issue #52325
624
660
_ => "used" ,
625
661
} ;
626
- self . warn_dead_code ( item. hir_id ( ) , span, item. ident . name , participle) ;
662
+ self . warn_dead_code ( item. hir_id ( ) , span, item. ident , participle, None ) ;
627
663
} else {
628
664
// Only continue if we didn't warn
629
665
intravisit:: walk_item ( self , item) ;
@@ -637,22 +673,28 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
637
673
id : hir:: HirId ,
638
674
) {
639
675
if self . should_warn_about_variant ( & variant) {
640
- self . warn_dead_code ( variant. id , variant. span , variant. ident . name , "constructed" ) ;
676
+ self . warn_dead_code ( variant. id , variant. span , variant. ident , "constructed" , None ) ;
641
677
} else {
642
678
intravisit:: walk_variant ( self , variant, g, id) ;
643
679
}
644
680
}
645
681
646
682
fn visit_foreign_item ( & mut self , fi : & ' tcx hir:: ForeignItem < ' tcx > ) {
647
683
if self . should_warn_about_foreign_item ( fi) {
648
- self . warn_dead_code ( fi. hir_id ( ) , fi. span , fi. ident . name , "used" ) ;
684
+ self . warn_dead_code ( fi. hir_id ( ) , fi. span , fi. ident , "used" , None ) ;
649
685
}
650
686
intravisit:: walk_foreign_item ( self , fi) ;
651
687
}
652
688
653
689
fn visit_field_def ( & mut self , field : & ' tcx hir:: FieldDef < ' tcx > ) {
654
690
if self . should_warn_about_field ( & field) {
655
- self . warn_dead_code ( field. hir_id , field. span , field. ident . name , "read" ) ;
691
+ self . warn_dead_code (
692
+ field. hir_id ,
693
+ field. span ,
694
+ field. ident ,
695
+ "read" ,
696
+ Some ( ExtraNote :: OtherPurposeExamples ) ,
697
+ ) ;
656
698
}
657
699
intravisit:: walk_field_def ( self , field) ;
658
700
}
@@ -664,8 +706,9 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
664
706
self . warn_dead_code (
665
707
impl_item. hir_id ( ) ,
666
708
impl_item. span ,
667
- impl_item. ident . name ,
709
+ impl_item. ident ,
668
710
"used" ,
711
+ None ,
669
712
) ;
670
713
}
671
714
self . visit_nested_body ( body_id)
@@ -683,7 +726,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
683
726
} else {
684
727
impl_item. ident . span
685
728
} ;
686
- self . warn_dead_code ( impl_item. hir_id ( ) , span, impl_item. ident . name , "used" ) ;
729
+ self . warn_dead_code ( impl_item. hir_id ( ) , span, impl_item. ident , "used" , None ) ;
687
730
}
688
731
self . visit_nested_body ( body_id)
689
732
}
0 commit comments