Rollup merge of #134979 - estebank:default-lint-sugg, r=compiler-errors
Provide structured suggestion for `impl Default` of type where all fields have defaults ``` error: `Default` impl doesn't use the declared default field values --> $DIR/manual-default-impl-could-be-derived.rs:28:1 | LL | / impl Default for B { LL | | fn default() -> Self { LL | | B { LL | | x: s(), | | --- this field has a default value LL | | y: 0, | | - this field has a default value ... | LL | | } | |_^ | help: to avoid divergence in behavior between `Struct { .. }` and `<Struct as Default>::default()`, derive the `Default` | LL ~ #[derive(Default)] struct B { | ``` Note that above the structured suggestion also includes completely removing the manual `impl`, but the rendering doesn't.
This commit is contained in:
commit
65cb7c66d0
2 changed files with 30 additions and 9 deletions
|
@ -1,9 +1,11 @@
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::Diag;
|
use rustc_errors::{Applicability, Diag};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::{declare_lint, impl_lint_pass};
|
use rustc_session::{declare_lint, impl_lint_pass};
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
use crate::{LateContext, LateLintPass};
|
use crate::{LateContext, LateLintPass};
|
||||||
|
@ -149,13 +151,16 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
|
||||||
let hir_id = cx.tcx.local_def_id_to_hir_id(local);
|
let hir_id = cx.tcx.local_def_id_to_hir_id(local);
|
||||||
let hir::Node::Item(item) = cx.tcx.hir_node(hir_id) else { return };
|
let hir::Node::Item(item) = cx.tcx.hir_node(hir_id) else { return };
|
||||||
cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, item.span, |diag| {
|
cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, item.span, |diag| {
|
||||||
mk_lint(diag, orig_fields, fields);
|
mk_lint(cx.tcx, diag, type_def_id, parent, orig_fields, fields);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_lint(
|
fn mk_lint(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
diag: &mut Diag<'_, ()>,
|
diag: &mut Diag<'_, ()>,
|
||||||
|
type_def_id: DefId,
|
||||||
|
impl_def_id: DefId,
|
||||||
orig_fields: FxHashMap<Symbol, &hir::FieldDef<'_>>,
|
orig_fields: FxHashMap<Symbol, &hir::FieldDef<'_>>,
|
||||||
fields: &[hir::ExprField<'_>],
|
fields: &[hir::ExprField<'_>],
|
||||||
) {
|
) {
|
||||||
|
@ -175,11 +180,24 @@ fn mk_lint(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diag.help(if removed_all_fields {
|
if removed_all_fields {
|
||||||
"to avoid divergence in behavior between `Struct { .. }` and \
|
let msg = "to avoid divergence in behavior between `Struct { .. }` and \
|
||||||
`<Struct as Default>::default()`, derive the `Default`"
|
`<Struct as Default>::default()`, derive the `Default`";
|
||||||
|
if let Some(hir::Node::Item(impl_)) = tcx.hir().get_if_local(impl_def_id) {
|
||||||
|
diag.multipart_suggestion_verbose(
|
||||||
|
msg,
|
||||||
|
vec![
|
||||||
|
(tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()),
|
||||||
|
(impl_.span, String::new()),
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
diag.help(msg);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
"use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them \
|
let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \
|
||||||
diverging over time"
|
avoid them diverging over time";
|
||||||
});
|
diag.help(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,10 @@ LL | | y: 0,
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
= help: to avoid divergence in behavior between `Struct { .. }` and `<Struct as Default>::default()`, derive the `Default`
|
help: to avoid divergence in behavior between `Struct { .. }` and `<Struct as Default>::default()`, derive the `Default`
|
||||||
|
|
|
||||||
|
LL ~ #[derive(Default)] struct B {
|
||||||
|
|
|
||||||
|
|
||||||
error: `Default` impl doesn't use the declared default field values
|
error: `Default` impl doesn't use the declared default field values
|
||||||
--> $DIR/manual-default-impl-could-be-derived.rs:43:1
|
--> $DIR/manual-default-impl-could-be-derived.rs:43:1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue