Skip to content

Commit 2b2ea9e

Browse files
committed
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.
1 parent 7a0cde9 commit 2b2ea9e

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

Diff for: compiler/rustc_lint/src/default_could_be_derived.rs

+26-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use rustc_data_structures::fx::FxHashMap;
2-
use rustc_errors::Diag;
2+
use rustc_errors::{Applicability, Diag};
33
use rustc_hir as hir;
44
use rustc_middle::ty;
5+
use rustc_middle::ty::TyCtxt;
56
use rustc_session::{declare_lint, impl_lint_pass};
67
use rustc_span::Symbol;
8+
use rustc_span::def_id::DefId;
79
use rustc_span::symbol::sym;
810

911
use crate::{LateContext, LateLintPass};
@@ -149,13 +151,16 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
149151
let hir_id = cx.tcx.local_def_id_to_hir_id(local);
150152
let hir::Node::Item(item) = cx.tcx.hir_node(hir_id) else { return };
151153
cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, item.span, |diag| {
152-
mk_lint(diag, orig_fields, fields);
154+
mk_lint(cx.tcx, diag, type_def_id, parent, orig_fields, fields);
153155
});
154156
}
155157
}
156158

157159
fn mk_lint(
160+
tcx: TyCtxt<'_>,
158161
diag: &mut Diag<'_, ()>,
162+
type_def_id: DefId,
163+
impl_def_id: DefId,
159164
orig_fields: FxHashMap<Symbol, &hir::FieldDef<'_>>,
160165
fields: &[hir::ExprField<'_>],
161166
) {
@@ -175,11 +180,24 @@ fn mk_lint(
175180
}
176181
}
177182

178-
diag.help(if removed_all_fields {
179-
"to avoid divergence in behavior between `Struct { .. }` and \
180-
`<Struct as Default>::default()`, derive the `Default`"
183+
if removed_all_fields {
184+
let msg = "to avoid divergence in behavior between `Struct { .. }` and \
185+
`<Struct as Default>::default()`, derive the `Default`";
186+
if let Some(hir::Node::Item(impl_)) = tcx.hir().get_if_local(impl_def_id) {
187+
diag.multipart_suggestion_verbose(
188+
msg,
189+
vec![
190+
(tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()),
191+
(impl_.span, String::new()),
192+
],
193+
Applicability::MachineApplicable,
194+
);
195+
} else {
196+
diag.help(msg);
197+
}
181198
} else {
182-
"use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them \
183-
diverging over time"
184-
});
199+
let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \
200+
avoid them diverging over time";
201+
diag.help(msg);
202+
}
185203
}

Diff for: tests/ui/structs/manual-default-impl-could-be-derived.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ LL | | y: 0,
3131
LL | | }
3232
| |_^
3333
|
34-
= help: to avoid divergence in behavior between `Struct { .. }` and `<Struct as Default>::default()`, derive the `Default`
34+
help: to avoid divergence in behavior between `Struct { .. }` and `<Struct as Default>::default()`, derive the `Default`
35+
|
36+
LL ~ #[derive(Default)] struct B {
37+
|
3538

3639
error: `Default` impl doesn't use the declared default field values
3740
--> $DIR/manual-default-impl-could-be-derived.rs:43:1

0 commit comments

Comments
 (0)