44
55use itertools:: Itertools ;
66use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
7- use rustc_errors:: { pluralize , Applicability , MultiSpan } ;
7+ use rustc_errors:: MultiSpan ;
88use rustc_hir as hir;
99use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
1010use rustc_hir:: def_id:: { DefId , LocalDefId } ;
@@ -18,7 +18,10 @@ use rustc_session::lint;
1818use rustc_span:: symbol:: { sym, Symbol } ;
1919use std:: mem;
2020
21- use crate :: errors:: UselessAssignment ;
21+ use crate :: errors:: {
22+ ChangeFieldsToBeOfUnitType , IgnoredDerivedImpls , MultipleDeadCodes , ParentInfo ,
23+ UselessAssignment ,
24+ } ;
2225
2326// Any local node that may call something in its body block should be
2427// explored. For example, if it's a live Node::Item that is a
@@ -693,99 +696,89 @@ impl<'tcx> DeadVisitor<'tcx> {
693696 parent_item : Option < LocalDefId > ,
694697 is_positional : bool ,
695698 ) {
696- if let Some ( & first_id) = dead_codes. first ( ) {
697- let tcx = self . tcx ;
698- let names: Vec < _ > = dead_codes
699- . iter ( )
700- . map ( |& def_id| tcx. item_name ( def_id. to_def_id ( ) ) . to_string ( ) )
701- . collect ( ) ;
702- let spans: Vec < _ > = dead_codes
703- . iter ( )
704- . map ( |& def_id| match tcx. def_ident_span ( def_id) {
705- Some ( s) => s. with_ctxt ( tcx. def_span ( def_id) . ctxt ( ) ) ,
706- None => tcx. def_span ( def_id) ,
699+ let Some ( & first_id) = dead_codes. first ( ) else {
700+ return ;
701+ } ;
702+ let tcx = self . tcx ;
703+ let names: Vec < _ > =
704+ dead_codes. iter ( ) . map ( |& def_id| tcx. item_name ( def_id. to_def_id ( ) ) ) . collect ( ) ;
705+ let spans: Vec < _ > = dead_codes
706+ . iter ( )
707+ . map ( |& def_id| match tcx. def_ident_span ( def_id) {
708+ Some ( s) => s. with_ctxt ( tcx. def_span ( def_id) . ctxt ( ) ) ,
709+ None => tcx. def_span ( def_id) ,
710+ } )
711+ . collect ( ) ;
712+
713+ let descr = tcx. def_kind ( first_id) . descr ( first_id. to_def_id ( ) ) ;
714+ let num = dead_codes. len ( ) ;
715+ let multiple = num > 6 ;
716+ let name_list = names. into ( ) ;
717+
718+ let lint = if is_positional {
719+ lint:: builtin:: UNUSED_TUPLE_STRUCT_FIELDS
720+ } else {
721+ lint:: builtin:: DEAD_CODE
722+ } ;
723+
724+ let parent_info = if let Some ( parent_item) = parent_item {
725+ let parent_descr = tcx. def_kind ( parent_item) . descr ( parent_item. to_def_id ( ) ) ;
726+ Some ( ParentInfo {
727+ num,
728+ descr,
729+ parent_descr,
730+ span : tcx. def_ident_span ( parent_item) . unwrap ( ) ,
731+ } )
732+ } else {
733+ None
734+ } ;
735+
736+ let encl_def_id = parent_item. unwrap_or ( first_id) ;
737+ let ignored_derived_impls =
738+ if let Some ( ign_traits) = self . ignored_derived_traits . get ( & encl_def_id) {
739+ let trait_list = ign_traits
740+ . iter ( )
741+ . map ( |( trait_id, _) | self . tcx . item_name ( * trait_id) )
742+ . collect :: < Vec < _ > > ( ) ;
743+ let trait_list_len = trait_list. len ( ) ;
744+ Some ( IgnoredDerivedImpls {
745+ name : self . tcx . item_name ( encl_def_id. to_def_id ( ) ) ,
746+ trait_list : trait_list. into ( ) ,
747+ trait_list_len,
707748 } )
708- . collect ( ) ;
709-
710- let descr = tcx. def_kind ( first_id) . descr ( first_id. to_def_id ( ) ) ;
711- let span_len = dead_codes. len ( ) ;
712- let names = match & names[ ..] {
713- _ if span_len > 6 => String :: new ( ) ,
714- [ name] => format ! ( "`{name}` " ) ,
715- [ names @ .., last] => {
716- format ! (
717- "{} and `{last}` " ,
718- names. iter( ) . map( |name| format!( "`{name}`" ) ) . join( ", " )
719- )
720- }
721- [ ] => unreachable ! ( ) ,
749+ } else {
750+ None
722751 } ;
723- let msg = format ! (
724- "{these}{descr}{s} {names}{are} never {participle}" ,
725- these = if span_len > 6 { "multiple " } else { "" } ,
726- s = pluralize!( span_len) ,
727- are = pluralize!( "is" , span_len) ,
728- ) ;
729-
730- tcx. struct_span_lint_hir (
731- if is_positional {
732- lint:: builtin:: UNUSED_TUPLE_STRUCT_FIELDS
733- } else {
734- lint:: builtin:: DEAD_CODE
735- } ,
736- tcx. hir ( ) . local_def_id_to_hir_id ( first_id) ,
737- MultiSpan :: from_spans ( spans. clone ( ) ) ,
738- msg,
739- |err| {
740- if is_positional {
741- err. multipart_suggestion (
742- & format ! (
743- "consider changing the field{s} to be of unit type to \
744- suppress this warning while preserving the field \
745- numbering, or remove the field{s}",
746- s = pluralize!( span_len)
747- ) ,
748- spans. iter ( ) . map ( |sp| ( * sp, "()" . to_string ( ) ) ) . collect ( ) ,
749- // "HasPlaceholders" because applying this fix by itself isn't
750- // enough: All constructor calls have to be adjusted as well
751- Applicability :: HasPlaceholders ,
752- ) ;
753- }
754752
755- if let Some ( parent_item) = parent_item {
756- let parent_descr = tcx. def_kind ( parent_item) . descr ( parent_item. to_def_id ( ) ) ;
757- err. span_label (
758- tcx. def_ident_span ( parent_item) . unwrap ( ) ,
759- format ! ( "{descr}{s} in this {parent_descr}" , s = pluralize!( span_len) ) ,
760- ) ;
761- }
753+ let diag = if is_positional {
754+ MultipleDeadCodes :: UnusedTupleStructFields {
755+ multiple,
756+ num,
757+ descr,
758+ participle,
759+ name_list,
760+ change_fields_suggestion : ChangeFieldsToBeOfUnitType { num, spans : spans. clone ( ) } ,
761+ parent_info,
762+ ignored_derived_impls,
763+ }
764+ } else {
765+ MultipleDeadCodes :: DeadCodes {
766+ multiple,
767+ num,
768+ descr,
769+ participle,
770+ name_list,
771+ parent_info,
772+ ignored_derived_impls,
773+ }
774+ } ;
762775
763- let encl_def_id = parent_item. unwrap_or ( first_id) ;
764- if let Some ( ign_traits) = self . ignored_derived_traits . get ( & encl_def_id) {
765- let traits_str = ign_traits
766- . iter ( )
767- . map ( |( trait_id, _) | format ! ( "`{}`" , self . tcx. item_name( * trait_id) ) )
768- . collect :: < Vec < _ > > ( )
769- . join ( " and " ) ;
770- let plural_s = pluralize ! ( ign_traits. len( ) ) ;
771- let article = if ign_traits. len ( ) > 1 { "" } else { "a " } ;
772- let is_are = if ign_traits. len ( ) > 1 { "these are" } else { "this is" } ;
773- let msg = format ! (
774- "`{}` has {}derived impl{} for the trait{} {}, but {} \
775- intentionally ignored during dead code analysis",
776- self . tcx. item_name( encl_def_id. to_def_id( ) ) ,
777- article,
778- plural_s,
779- plural_s,
780- traits_str,
781- is_are
782- ) ;
783- err. note ( & msg) ;
784- }
785- err
786- } ,
787- ) ;
788- }
776+ self . tcx . emit_spanned_lint (
777+ lint,
778+ tcx. hir ( ) . local_def_id_to_hir_id ( first_id) ,
779+ MultiSpan :: from_spans ( spans. clone ( ) ) ,
780+ diag,
781+ ) ;
789782 }
790783
791784 fn warn_dead_fields_and_variants (
0 commit comments