]> git.lizzy.rs Git - rust.git/commitdiff
Port `dead_code` lints to be translatable.
authorCharles Lew <crlf0710@gmail.com>
Sat, 22 Oct 2022 10:48:20 +0000 (18:48 +0800)
committerCharles Lew <crlf0710@gmail.com>
Mon, 24 Oct 2022 09:02:31 +0000 (17:02 +0800)
compiler/rustc_error_messages/locales/en-US/passes.ftl
compiler/rustc_errors/src/diagnostic_impls.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/errors.rs
src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
src/test/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.rs
src/test/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr
src/test/ui/lint/dead-code/tuple-struct-field.rs
src/test/ui/lint/dead-code/tuple-struct-field.stderr

index 4bc6bd9fb220791c5a5664a45d8fb9b0b25ddc91..a5b002fa3579e053513eed81a4bae19892f75e3b 100644 (file)
@@ -671,3 +671,37 @@ passes_missing_const_err =
     attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
     .help = make the function or method const
     .label = attribute specified here
+
+passes_dead_codes =
+    { $multiple ->
+      *[true] multiple {$descr}s are
+       [false] { $num ->
+         [one] {$descr} {$name_list} is
+        *[other] {$descr}s {$name_list} are
+       }
+    } never {$participle}
+
+passes_change_fields_to_be_of_unit_type =
+    consider changing the { $num ->
+      [one] field
+     *[other] fields
+    } to be of unit type to suppress this warning
+    while preserving the field numbering, or remove the { $num ->
+      [one] field
+     *[other] fields
+    }
+
+passes_parent_info =
+    {$num ->
+      [one] {$descr}
+     *[other] {$descr}s
+    } in this {$parent_descr}
+
+passes_ignored_derived_impls =
+    `{$name}` has {$trait_list_len ->
+      [one] a derived impl
+     *[other] derived impls
+    } for the {$trait_list_len ->
+      [one] trait {$trait_list}, but this is
+     *[other] traits {$trait_list}, but these are
+    } intentionally ignored during dead code analysis
index 7640b2919f78b6fc30339a666c8a27927b668ebe..f6fe9192b45ca1565baad38de990f5cae1f07f83 100644 (file)
@@ -11,6 +11,7 @@
 use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
 use std::borrow::Cow;
 use std::fmt;
+use std::fmt::Write;
 use std::num::ParseIntError;
 use std::path::{Path, PathBuf};
 
@@ -170,6 +171,37 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
     }
 }
 
+#[derive(Clone)]
+pub struct DiagnosticSymbolList(Vec<Symbol>);
+
+impl From<Vec<Symbol>> for DiagnosticSymbolList {
+    fn from(v: Vec<Symbol>) -> Self {
+        DiagnosticSymbolList(v)
+    }
+}
+
+impl IntoDiagnosticArg for DiagnosticSymbolList {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        // FIXME: replace the logic here with a real list formatter
+        let symbols = match &self.0[..] {
+            [symbol] => format!("`{symbol}`"),
+            [symbol, last] => {
+                format!("`{symbol}` and `{last}`",)
+            }
+            [symbols @ .., last] => {
+                let mut result = String::new();
+                for symbol in symbols {
+                    write!(result, "`{symbol}`, ").unwrap();
+                }
+                write!(result, "and `{last}`").unwrap();
+                result
+            }
+            [] => unreachable!(),
+        };
+        DiagnosticArgValue::Str(Cow::Owned(symbols))
+    }
+}
+
 impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
     fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
         let mut diag;
index 0963ea71f80236ac51c1e7bc70781f069ea8a2ec..2c8a70981bc72b3a391a2a41d7a83e9e73836e94 100644 (file)
@@ -376,7 +376,7 @@ impl error::Error for ExplicitBug {}
     DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
 };
 pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
-pub use diagnostic_impls::DiagnosticArgFromDisplay;
+pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList};
 use std::backtrace::Backtrace;
 
 /// A handler deals with errors and other compiler output.
index 6a97ad3fe86e2cc367a425c92490400ed1bc279f..9157c8279a5c280e8889283b18ca9c0f90d14280 100644 (file)
@@ -4,7 +4,7 @@
 
 use itertools::Itertools;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, Applicability, MultiSpan};
+use rustc_errors::MultiSpan;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::{sym, Symbol};
 use std::mem;
 
-use crate::errors::UselessAssignment;
+use crate::errors::{
+    ChangeFieldsToBeOfUnitType, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo,
+    UselessAssignment,
+};
 
 // Any local node that may call something in its body block should be
 // explored. For example, if it's a live Node::Item that is a
@@ -698,99 +701,89 @@ fn warn_multiple_dead_codes(
         parent_item: Option<LocalDefId>,
         is_positional: bool,
     ) {
-        if let Some(&first_id) = dead_codes.first() {
-            let tcx = self.tcx;
-            let names: Vec<_> = dead_codes
-                .iter()
-                .map(|&def_id| tcx.item_name(def_id.to_def_id()).to_string())
-                .collect();
-            let spans: Vec<_> = dead_codes
-                .iter()
-                .map(|&def_id| match tcx.def_ident_span(def_id) {
-                    Some(s) => s.with_ctxt(tcx.def_span(def_id).ctxt()),
-                    None => tcx.def_span(def_id),
+        let Some(&first_id) = dead_codes.first() else {
+            return;
+        };
+        let tcx = self.tcx;
+        let names: Vec<_> =
+            dead_codes.iter().map(|&def_id| tcx.item_name(def_id.to_def_id())).collect();
+        let spans: Vec<_> = dead_codes
+            .iter()
+            .map(|&def_id| match tcx.def_ident_span(def_id) {
+                Some(s) => s.with_ctxt(tcx.def_span(def_id).ctxt()),
+                None => tcx.def_span(def_id),
+            })
+            .collect();
+
+        let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
+        let num = dead_codes.len();
+        let multiple = num > 6;
+        let name_list = names.into();
+
+        let lint = if is_positional {
+            lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
+        } else {
+            lint::builtin::DEAD_CODE
+        };
+
+        let parent_info = if let Some(parent_item) = parent_item {
+            let parent_descr = tcx.def_kind(parent_item).descr(parent_item.to_def_id());
+            Some(ParentInfo {
+                num,
+                descr,
+                parent_descr,
+                span: tcx.def_ident_span(parent_item).unwrap(),
+            })
+        } else {
+            None
+        };
+
+        let encl_def_id = parent_item.unwrap_or(first_id);
+        let ignored_derived_impls =
+            if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) {
+                let trait_list = ign_traits
+                    .iter()
+                    .map(|(trait_id, _)| self.tcx.item_name(*trait_id))
+                    .collect::<Vec<_>>();
+                let trait_list_len = trait_list.len();
+                Some(IgnoredDerivedImpls {
+                    name: self.tcx.item_name(encl_def_id.to_def_id()),
+                    trait_list: trait_list.into(),
+                    trait_list_len,
                 })
-                .collect();
-
-            let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
-            let span_len = dead_codes.len();
-            let names = match &names[..] {
-                _ if span_len > 6 => String::new(),
-                [name] => format!("`{name}` "),
-                [names @ .., last] => {
-                    format!(
-                        "{} and `{last}` ",
-                        names.iter().map(|name| format!("`{name}`")).join(", ")
-                    )
-                }
-                [] => unreachable!(),
+            } else {
+                None
             };
-            let msg = format!(
-                "{these}{descr}{s} {names}{are} never {participle}",
-                these = if span_len > 6 { "multiple " } else { "" },
-                s = pluralize!(span_len),
-                are = pluralize!("is", span_len),
-            );
-
-            tcx.struct_span_lint_hir(
-                if is_positional {
-                    lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
-                } else {
-                    lint::builtin::DEAD_CODE
-                },
-                tcx.hir().local_def_id_to_hir_id(first_id),
-                MultiSpan::from_spans(spans.clone()),
-                msg,
-                |err| {
-                    if is_positional {
-                        err.multipart_suggestion(
-                            &format!(
-                                "consider changing the field{s} to be of unit type to \
-                                      suppress this warning while preserving the field \
-                                      numbering, or remove the field{s}",
-                                s = pluralize!(span_len)
-                            ),
-                            spans.iter().map(|sp| (*sp, "()".to_string())).collect(),
-                            // "HasPlaceholders" because applying this fix by itself isn't
-                            // enough: All constructor calls have to be adjusted as well
-                            Applicability::HasPlaceholders,
-                        );
-                    }
 
-                    if let Some(parent_item) = parent_item {
-                        let parent_descr = tcx.def_kind(parent_item).descr(parent_item.to_def_id());
-                        err.span_label(
-                            tcx.def_ident_span(parent_item).unwrap(),
-                            format!("{descr}{s} in this {parent_descr}", s = pluralize!(span_len)),
-                        );
-                    }
+        let diag = if is_positional {
+            MultipleDeadCodes::UnusedTupleStructFields {
+                multiple,
+                num,
+                descr,
+                participle,
+                name_list,
+                change_fields_suggestion: ChangeFieldsToBeOfUnitType { num, spans: spans.clone() },
+                parent_info,
+                ignored_derived_impls,
+            }
+        } else {
+            MultipleDeadCodes::DeadCodes {
+                multiple,
+                num,
+                descr,
+                participle,
+                name_list,
+                parent_info,
+                ignored_derived_impls,
+            }
+        };
 
-                    let encl_def_id = parent_item.unwrap_or(first_id);
-                    if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) {
-                        let traits_str = ign_traits
-                            .iter()
-                            .map(|(trait_id, _)| format!("`{}`", self.tcx.item_name(*trait_id)))
-                            .collect::<Vec<_>>()
-                            .join(" and ");
-                        let plural_s = pluralize!(ign_traits.len());
-                        let article = if ign_traits.len() > 1 { "" } else { "a " };
-                        let is_are = if ign_traits.len() > 1 { "these are" } else { "this is" };
-                        let msg = format!(
-                            "`{}` has {}derived impl{} for the trait{} {}, but {} \
-                            intentionally ignored during dead code analysis",
-                            self.tcx.item_name(encl_def_id.to_def_id()),
-                            article,
-                            plural_s,
-                            plural_s,
-                            traits_str,
-                            is_are
-                        );
-                        err.note(&msg);
-                    }
-                    err
-                },
-            );
-        }
+        self.tcx.emit_spanned_lint(
+            lint,
+            tcx.hir().local_def_id_to_hir_id(first_id),
+            MultiSpan::from_spans(spans.clone()),
+            diag,
+        );
     }
 
     fn warn_dead_fields_and_variants(
index adaaf5392425b6805b454ca4acc914484fb7b4d0..d39d7629b287f9e767a5313c2a403708cffadf20 100644 (file)
@@ -4,12 +4,16 @@
 };
 
 use rustc_ast::Label;
-use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
+use rustc_errors::{
+    error_code, Applicability, DiagnosticSymbolList, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
+};
 use rustc_hir::{self as hir, ExprKind, Target};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{MainDefinition, Ty};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
+use rustc_errors::{pluralize, AddToDiagnostic, Diagnostic, SubdiagnosticMessage};
+
 use crate::lang_items::Duplicate;
 
 #[derive(LintDiagnostic)]
@@ -1449,3 +1453,77 @@ pub struct MissingConstErr {
     #[label]
     pub const_span: Span,
 }
+
+#[derive(LintDiagnostic)]
+pub enum MultipleDeadCodes<'tcx> {
+    #[diag(passes_dead_codes)]
+    DeadCodes {
+        multiple: bool,
+        num: usize,
+        descr: &'tcx str,
+        participle: &'tcx str,
+        name_list: DiagnosticSymbolList,
+        #[subdiagnostic]
+        parent_info: Option<ParentInfo<'tcx>>,
+        #[subdiagnostic]
+        ignored_derived_impls: Option<IgnoredDerivedImpls>,
+    },
+    #[diag(passes_dead_codes)]
+    UnusedTupleStructFields {
+        multiple: bool,
+        num: usize,
+        descr: &'tcx str,
+        participle: &'tcx str,
+        name_list: DiagnosticSymbolList,
+        #[subdiagnostic]
+        change_fields_suggestion: ChangeFieldsToBeOfUnitType,
+        #[subdiagnostic]
+        parent_info: Option<ParentInfo<'tcx>>,
+        #[subdiagnostic]
+        ignored_derived_impls: Option<IgnoredDerivedImpls>,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[label(passes_parent_info)]
+pub struct ParentInfo<'tcx> {
+    pub num: usize,
+    pub descr: &'tcx str,
+    pub parent_descr: &'tcx str,
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[note(passes_ignored_derived_impls)]
+pub struct IgnoredDerivedImpls {
+    pub name: Symbol,
+    pub trait_list: DiagnosticSymbolList,
+    pub trait_list_len: usize,
+}
+
+pub struct ChangeFieldsToBeOfUnitType {
+    pub num: usize,
+    pub spans: Vec<Span>,
+}
+
+// FIXME: Replace this impl with a derive.
+impl AddToDiagnostic for ChangeFieldsToBeOfUnitType {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        diag.multipart_suggestion(
+            &format!(
+                "consider changing the field{s} to be of unit type to \
+                          suppress this warning while preserving the field \
+                          numbering, or remove the field{s}",
+                s = pluralize!(self.num)
+            ),
+            self.spans.iter().map(|sp| (*sp, "()".to_string())).collect(),
+            // "HasPlaceholders" because applying this fix by itself isn't
+            // enough: All constructor calls have to be adjusted as well
+            Applicability::HasPlaceholders,
+        );
+    }
+}
index 15d06817577ea2bd51650b114ba024475280bef7..6ab1fb7b039bd6ec63c06fb4d12b478275296355 100644 (file)
@@ -3,7 +3,7 @@
 #[derive(Debug)]
 pub struct Whatever {
     pub field0: (),
-    field1: (), //~ ERROR fields `field1`, `field2`, `field3` and `field4` are never read
+    field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read
     field2: (),
     field3: (),
     field4: (),
index 512b870fa4b6c323fe117cefe2b3547477b289a5..7f4f78cebc9189d72d6c168ad6ab763e7c1a9fea 100644 (file)
@@ -1,4 +1,4 @@
-error: fields `field1`, `field2`, `field3` and `field4` are never read
+error: fields `field1`, `field2`, `field3`, and `field4` are never read
   --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
    |
 LL | pub struct Whatever {
index e3935cf9149bb63bfbaf923457434353b903586e..2003e1e293a58c18a31b372068690631a14f0110 100644 (file)
@@ -7,7 +7,7 @@ struct Bar {
     b: usize, //~ ERROR field `b` is never read
     #[deny(dead_code)]
     c: usize, //~ ERROR fields `c` and `e` are never read
-    d: usize, //~ WARN fields `d`, `f` and `g` are never read
+    d: usize, //~ WARN fields `d`, `f`, and `g` are never read
     #[deny(dead_code)]
     e: usize,
     f: usize,
index c0f1ed38f6de3bd9cb5512ce587f95dacba2bda8..0e5c78a7167975dc89aad27ace64ecdc41e2726a 100644 (file)
@@ -1,4 +1,4 @@
-warning: fields `d`, `f` and `g` are never read
+warning: fields `d`, `f`, and `g` are never read
   --> $DIR/multiple-dead-codes-in-the-same-struct.rs:10:5
    |
 LL | struct Bar {
index b15d706368633e3e9cd9142f7462ad97c60228cf..14fb30be949dc2b45ca98d49790b0a34e79919dd 100644 (file)
@@ -11,7 +11,7 @@
 //~| HELP: consider changing the field to be of unit type
 
 struct MultipleUnused(i32, f32, String, u8);
-//~^ ERROR: fields `0`, `1`, `2` and `3` are never read
+//~^ ERROR: fields `0`, `1`, `2`, and `3` are never read
 //~| NOTE: fields in this struct
 //~| HELP: consider changing the fields to be of unit type
 
index ca0989f5b987f145864975465db9f0935fd0b603..b8ad5cbe4e9779d11e2fba8cecd43f27f4c86dcd 100644 (file)
@@ -16,7 +16,7 @@ help: consider changing the field to be of unit type to suppress this warning wh
 LL | struct SingleUnused(i32, (), String);
    |                          ~~
 
-error: fields `0`, `1`, `2` and `3` are never read
+error: fields `0`, `1`, `2`, and `3` are never read
   --> $DIR/tuple-struct-field.rs:13:23
    |
 LL | struct MultipleUnused(i32, f32, String, u8);