diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2024-12-31 18:06:01 +0000 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2024-12-31 18:06:01 +0000 |
| commit | 2b2ea9e875dc9ae6c2d351078f1f43e533c9d780 (patch) | |
| tree | dbbc1294b034869d46a03d36449b1ea29f44c9ea | |
| parent | 7a0cde96f83c6d38237bb8062df6300ecf4c2687 (diff) | |
| download | rust-2b2ea9e875dc9ae6c2d351078f1f43e533c9d780.tar.gz rust-2b2ea9e875dc9ae6c2d351078f1f43e533c9d780.zip | |
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.
| -rw-r--r-- | compiler/rustc_lint/src/default_could_be_derived.rs | 34 | ||||
| -rw-r--r-- | tests/ui/structs/manual-default-impl-could-be-derived.stderr | 5 |
2 files changed, 30 insertions, 9 deletions
diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index d95cbb05158..bae9defa687 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -1,9 +1,11 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_errors::Diag; +use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_middle::ty; +use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::Symbol; +use rustc_span::def_id::DefId; use rustc_span::symbol::sym; 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::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| { - mk_lint(diag, orig_fields, fields); + mk_lint(cx.tcx, diag, type_def_id, parent, orig_fields, fields); }); } } fn mk_lint( + tcx: TyCtxt<'_>, diag: &mut Diag<'_, ()>, + type_def_id: DefId, + impl_def_id: DefId, orig_fields: FxHashMap<Symbol, &hir::FieldDef<'_>>, fields: &[hir::ExprField<'_>], ) { @@ -175,11 +180,24 @@ fn mk_lint( } } - diag.help(if removed_all_fields { - "to avoid divergence in behavior between `Struct { .. }` and \ - `<Struct as Default>::default()`, derive the `Default`" + if removed_all_fields { + let msg = "to avoid divergence in behavior between `Struct { .. }` and \ + `<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 { - "use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them \ - diverging over time" - }); + let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \ + avoid them diverging over time"; + diag.help(msg); + } } diff --git a/tests/ui/structs/manual-default-impl-could-be-derived.stderr b/tests/ui/structs/manual-default-impl-could-be-derived.stderr index e8f607fac7e..cf06d5418e1 100644 --- a/tests/ui/structs/manual-default-impl-could-be-derived.stderr +++ b/tests/ui/structs/manual-default-impl-could-be-derived.stderr @@ -31,7 +31,10 @@ LL | | y: 0, 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 --> $DIR/manual-default-impl-could-be-derived.rs:43:1 |
