File tree Expand file tree Collapse file tree 4 files changed +93
-38
lines changed Expand file tree Collapse file tree 4 files changed +93
-38
lines changed Original file line number Diff line number Diff line change @@ -133,9 +133,9 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
133133 // }
134134 //
135135 // We suggest #[derive(Default)] if
136- // - `val` is `Default::default()`
137- // - `val` is `0`
138- // - `val` is `false`
136+ // - `val` is `Default::default()`
137+ // - `val` is `0`
138+ // - `val` is `false`
139139 fn check_expr ( tcx : TyCtxt < ' _ > , kind : hir:: ExprKind < ' _ > ) -> bool {
140140 match kind {
141141 hir:: ExprKind :: Lit ( spanned_lit) => match spanned_lit. node {
@@ -152,9 +152,20 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
152152 // field: Default::default(),
153153 true
154154 }
155- _ => {
156- false
155+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) )
156+ if let Res :: Def (
157+ DefKind :: Ctor ( CtorOf :: Variant , CtorKind :: Const ) ,
158+ def_id,
159+ ) = path. res
160+ && let def_id = tcx. parent ( def_id) // From Ctor to variant
161+ && tcx. is_lang_item ( def_id, hir:: LangItem :: OptionNone ) =>
162+ {
163+ // FIXME: We should use a better check where we explore existing
164+ // `impl Default for def_id` of the found type and see compare them
165+ // against what we have here. For now, special case `Option::None`.
166+ true
157167 }
168+ _ => false ,
158169 }
159170 }
160171 if fields. iter ( ) . all ( |f| check_expr ( cx. tcx , f. expr . kind ) ) {
Original file line number Diff line number Diff line change 2525// }
2626//
2727
28+ // Explicit check against numeric literals and `Default::default()` calls.
2829#[derive(Default)] struct D {
2930 x: Option<i32>,
3031 y: i32,
3132}
3233
33- //
34- // #[derive(Debug)]
35- // struct E {
36- // x: Option<i32>,
37- // }
38- //
39- // impl Default for E {
40- // fn default() -> Self {
41- // E {
42- // x: None,
43- // }
44- // }
45- // }
4634
35+ // Explicit check against `None` literal, in the same way that we check against numeric literals.
36+ #[derive(Debug)]
37+ #[derive(Default)] struct E {
38+ x: Option<i32>,
39+ }
40+
41+
42+ // Detection of unit variant ctors that could have been marked `#[default]`.
4743#[derive(Default)] enum F {
4844 #[default] Unit,
4945 Tuple(i32),
5046}
5147
5248
49+ // Comparison of `impl` *fields* with their `Default::default()` bodies.
50+ // struct G {
51+ // f: F,
52+ // }
53+
54+ // impl Default for G {
55+ // fn default() -> Self {
56+ // G {
57+ // f: F::Unit,
58+ // }
59+ // }
60+ // }
61+
5362fn main() {
5463// let _ = A::default();
5564// let _ = B::default();
5665// let _ = C::default();
57- // let _ = D::default();
58- // let _ = E::default();
66+ let _ = D::default();
67+ let _ = E::default();
5968 let _ = F::default();
69+ // let _ = G::default();
6070}
Original file line number Diff line number Diff line change 2525// }
2626//
2727
28+ // Explicit check against numeric literals and `Default::default()` calls.
2829struct D {
2930 x : Option < i32 > ,
3031 y : i32 ,
@@ -38,20 +39,22 @@ impl Default for D { //~ ERROR
3839 }
3940 }
4041}
41- //
42- // #[derive(Debug)]
43- // struct E {
44- // x: Option<i32>,
45- // }
46- //
47- // impl Default for E {
48- // fn default() -> Self {
49- // E {
50- // x: None,
51- // }
52- // }
53- // }
5442
43+ // Explicit check against `None` literal, in the same way that we check against numeric literals.
44+ #[ derive( Debug ) ]
45+ struct E {
46+ x : Option < i32 > ,
47+ }
48+
49+ impl Default for E { //~ ERROR
50+ fn default ( ) -> Self {
51+ E {
52+ x : None ,
53+ }
54+ }
55+ }
56+
57+ // Detection of unit variant ctors that could have been marked `#[default]`.
5558enum F {
5659 Unit ,
5760 Tuple ( i32 ) ,
@@ -63,11 +66,25 @@ impl Default for F { //~ ERROR
6366 }
6467}
6568
69+ // Comparison of `impl` *fields* with their `Default::default()` bodies.
70+ // struct G {
71+ // f: F,
72+ // }
73+
74+ // impl Default for G {
75+ // fn default() -> Self {
76+ // G {
77+ // f: F::Unit,
78+ // }
79+ // }
80+ // }
81+
6682fn main ( ) {
6783// let _ = A::default();
6884// let _ = B::default();
6985// let _ = C::default();
70- // let _ = D::default();
71- // let _ = E::default();
86+ let _ = D :: default ( ) ;
87+ let _ = E :: default ( ) ;
7288 let _ = F :: default ( ) ;
89+ // let _ = G::default();
7390}
Original file line number Diff line number Diff line change 11error: `impl Default` that could be derived
2- --> $DIR/manual-default-impl-could-be-derived.rs:33 :1
2+ --> $DIR/manual-default-impl-could-be-derived.rs:34 :1
33 |
44LL | / impl Default for D {
55LL | | fn default() -> Self {
@@ -21,7 +21,24 @@ LL ~ #[derive(Default)] struct D {
2121 |
2222
2323error: `impl Default` that could be derived
24- --> $DIR/manual-default-impl-could-be-derived.rs:60:1
24+ --> $DIR/manual-default-impl-could-be-derived.rs:49:1
25+ |
26+ LL | / impl Default for E {
27+ LL | | fn default() -> Self {
28+ LL | | E {
29+ LL | | x: None,
30+ LL | | }
31+ LL | | }
32+ LL | | }
33+ | |_^
34+ |
35+ help: you don't need to manually `impl Default`, you can derive it
36+ |
37+ LL ~ #[derive(Default)] struct E {
38+ |
39+
40+ error: `impl Default` that could be derived
41+ --> $DIR/manual-default-impl-could-be-derived.rs:63:1
2542 |
2643LL | / impl Default for F {
2744LL | | fn default() -> Self {
@@ -36,5 +53,5 @@ LL ~ #[derive(Default)] enum F {
3653LL ~ #[default] Unit,
3754 |
3855
39- error: aborting due to 2 previous errors
56+ error: aborting due to 3 previous errors
4057
You can’t perform that action at this time.
0 commit comments