mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-28 15:43:21 +00:00
Rollup merge of #103397 - crlf0710:port_dead_code_lint, r=davidtwco
Port `dead_code` lints to be translatable. This adds an additional comma to lists with three or more items, to be consistent with list formatters like `icu4x`. r? `@davidtwco`
This commit is contained in:
commit
612bb7890c
@ -665,3 +665,36 @@ 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
|
||||
|
@ -11,6 +11,7 @@ use rustc_target::abi::TargetDataLayoutErrors;
|
||||
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 @@ impl IntoDiagnosticArg for Level {
|
||||
}
|
||||
}
|
||||
|
||||
#[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;
|
||||
|
@ -376,7 +376,7 @@ pub use diagnostic::{
|
||||
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.
|
||||
|
@ -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};
|
||||
@ -18,7 +18,10 @@ use rustc_session::lint;
|
||||
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
|
||||
@ -693,99 +696,89 @@ impl<'tcx> DeadVisitor<'tcx> {
|
||||
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,
|
||||
);
|
||||
}
|
||||
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,
|
||||
}
|
||||
};
|
||||
|
||||
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 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(
|
||||
|
@ -4,7 +4,9 @@ use std::{
|
||||
};
|
||||
|
||||
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};
|
||||
@ -1446,3 +1448,59 @@ 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,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(passes_change_fields_to_be_of_unit_type, applicability = "has-placeholders")]
|
||||
pub struct ChangeFieldsToBeOfUnitType {
|
||||
pub num: usize,
|
||||
#[suggestion_part(code = "()")]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
@ -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: (),
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -11,7 +11,7 @@ struct SingleUnused(i32, [u8; LEN], String);
|
||||
//~| 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
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user