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
@@ -698,99 +701,89 @@ impl<'tcx> DeadVisitor<'tcx> {
698701 parent_item : Option < LocalDefId > ,
699702 is_positional : bool ,
700703 ) {
701- if let Some ( & first_id) = dead_codes. first ( ) {
702- let tcx = self . tcx ;
703- let names: Vec < _ > = dead_codes
704- . iter ( )
705- . map ( |& def_id| tcx. item_name ( def_id. to_def_id ( ) ) . to_string ( ) )
706- . collect ( ) ;
707- let spans: Vec < _ > = dead_codes
708- . iter ( )
709- . map ( |& def_id| match tcx. def_ident_span ( def_id) {
710- Some ( s) => s. with_ctxt ( tcx. def_span ( def_id) . ctxt ( ) ) ,
711- None => tcx. def_span ( def_id) ,
704+ let Some ( & first_id) = dead_codes. first ( ) else {
705+ return ;
706+ } ;
707+ let tcx = self . tcx ;
708+ let names: Vec < _ > =
709+ dead_codes. iter ( ) . map ( |& def_id| tcx. item_name ( def_id. to_def_id ( ) ) ) . collect ( ) ;
710+ let spans: Vec < _ > = dead_codes
711+ . iter ( )
712+ . map ( |& def_id| match tcx. def_ident_span ( def_id) {
713+ Some ( s) => s. with_ctxt ( tcx. def_span ( def_id) . ctxt ( ) ) ,
714+ None => tcx. def_span ( def_id) ,
715+ } )
716+ . collect ( ) ;
717+
718+ let descr = tcx. def_kind ( first_id) . descr ( first_id. to_def_id ( ) ) ;
719+ let num = dead_codes. len ( ) ;
720+ let multiple = num > 6 ;
721+ let name_list = names. into ( ) ;
722+
723+ let lint = if is_positional {
724+ lint:: builtin:: UNUSED_TUPLE_STRUCT_FIELDS
725+ } else {
726+ lint:: builtin:: DEAD_CODE
727+ } ;
728+
729+ let parent_info = if let Some ( parent_item) = parent_item {
730+ let parent_descr = tcx. def_kind ( parent_item) . descr ( parent_item. to_def_id ( ) ) ;
731+ Some ( ParentInfo {
732+ num,
733+ descr,
734+ parent_descr,
735+ span : tcx. def_ident_span ( parent_item) . unwrap ( ) ,
736+ } )
737+ } else {
738+ None
739+ } ;
740+
741+ let encl_def_id = parent_item. unwrap_or ( first_id) ;
742+ let ignored_derived_impls =
743+ if let Some ( ign_traits) = self . ignored_derived_traits . get ( & encl_def_id) {
744+ let trait_list = ign_traits
745+ . iter ( )
746+ . map ( |( trait_id, _) | self . tcx . item_name ( * trait_id) )
747+ . collect :: < Vec < _ > > ( ) ;
748+ let trait_list_len = trait_list. len ( ) ;
749+ Some ( IgnoredDerivedImpls {
750+ name : self . tcx . item_name ( encl_def_id. to_def_id ( ) ) ,
751+ trait_list : trait_list. into ( ) ,
752+ trait_list_len,
712753 } )
713- . collect ( ) ;
714-
715- let descr = tcx. def_kind ( first_id) . descr ( first_id. to_def_id ( ) ) ;
716- let span_len = dead_codes. len ( ) ;
717- let names = match & names[ ..] {
718- _ if span_len > 6 => String :: new ( ) ,
719- [ name] => format ! ( "`{name}` " ) ,
720- [ names @ .., last] => {
721- format ! (
722- "{} and `{last}` " ,
723- names. iter( ) . map( |name| format!( "`{name}`" ) ) . join( ", " )
724- )
725- }
726- [ ] => unreachable ! ( ) ,
754+ } else {
755+ None
727756 } ;
728- let msg = format ! (
729- "{these}{descr}{s} {names}{are} never {participle}" ,
730- these = if span_len > 6 { "multiple " } else { "" } ,
731- s = pluralize!( span_len) ,
732- are = pluralize!( "is" , span_len) ,
733- ) ;
734-
735- tcx. struct_span_lint_hir (
736- if is_positional {
737- lint:: builtin:: UNUSED_TUPLE_STRUCT_FIELDS
738- } else {
739- lint:: builtin:: DEAD_CODE
740- } ,
741- tcx. hir ( ) . local_def_id_to_hir_id ( first_id) ,
742- MultiSpan :: from_spans ( spans. clone ( ) ) ,
743- msg,
744- |err| {
745- if is_positional {
746- err. multipart_suggestion (
747- & format ! (
748- "consider changing the field{s} to be of unit type to \
749- suppress this warning while preserving the field \
750- numbering, or remove the field{s}",
751- s = pluralize!( span_len)
752- ) ,
753- spans. iter ( ) . map ( |sp| ( * sp, "()" . to_string ( ) ) ) . collect ( ) ,
754- // "HasPlaceholders" because applying this fix by itself isn't
755- // enough: All constructor calls have to be adjusted as well
756- Applicability :: HasPlaceholders ,
757- ) ;
758- }
759757
760- if let Some ( parent_item) = parent_item {
761- let parent_descr = tcx. def_kind ( parent_item) . descr ( parent_item. to_def_id ( ) ) ;
762- err. span_label (
763- tcx. def_ident_span ( parent_item) . unwrap ( ) ,
764- format ! ( "{descr}{s} in this {parent_descr}" , s = pluralize!( span_len) ) ,
765- ) ;
766- }
758+ let diag = if is_positional {
759+ MultipleDeadCodes :: UnusedTupleStructFields {
760+ multiple,
761+ num,
762+ descr,
763+ participle,
764+ name_list,
765+ change_fields_suggestion : ChangeFieldsToBeOfUnitType { num, spans : spans. clone ( ) } ,
766+ parent_info,
767+ ignored_derived_impls,
768+ }
769+ } else {
770+ MultipleDeadCodes :: DeadCodes {
771+ multiple,
772+ num,
773+ descr,
774+ participle,
775+ name_list,
776+ parent_info,
777+ ignored_derived_impls,
778+ }
779+ } ;
767780
768- let encl_def_id = parent_item. unwrap_or ( first_id) ;
769- if let Some ( ign_traits) = self . ignored_derived_traits . get ( & encl_def_id) {
770- let traits_str = ign_traits
771- . iter ( )
772- . map ( |( trait_id, _) | format ! ( "`{}`" , self . tcx. item_name( * trait_id) ) )
773- . collect :: < Vec < _ > > ( )
774- . join ( " and " ) ;
775- let plural_s = pluralize ! ( ign_traits. len( ) ) ;
776- let article = if ign_traits. len ( ) > 1 { "" } else { "a " } ;
777- let is_are = if ign_traits. len ( ) > 1 { "these are" } else { "this is" } ;
778- let msg = format ! (
779- "`{}` has {}derived impl{} for the trait{} {}, but {} \
780- intentionally ignored during dead code analysis",
781- self . tcx. item_name( encl_def_id. to_def_id( ) ) ,
782- article,
783- plural_s,
784- plural_s,
785- traits_str,
786- is_are
787- ) ;
788- err. note ( & msg) ;
789- }
790- err
791- } ,
792- ) ;
793- }
781+ self . tcx . emit_spanned_lint (
782+ lint,
783+ tcx. hir ( ) . local_def_id_to_hir_id ( first_id) ,
784+ MultiSpan :: from_spans ( spans. clone ( ) ) ,
785+ diag,
786+ ) ;
794787 }
795788
796789 fn warn_dead_fields_and_variants (
0 commit comments