@@ -20,8 +20,8 @@ declare_lint! {
20
20
/// }
21
21
///
22
22
/// #[deny(default_could_be_derived)]
23
- /// impl Default for Foo {
24
- /// fn default() -> Foo {
23
+ /// impl Default for A {
24
+ /// fn default() -> A {
25
25
/// A {
26
26
/// b: None,
27
27
/// }
@@ -59,8 +59,9 @@ declare_lint! {
59
59
}
60
60
61
61
declare_lint ! {
62
- /// The `default_could_be_derived` lint checks for manual `impl` blocks
63
- /// of the `Default` trait that could have been derived.
62
+ /// The `manual_default_for_type_with_default_fields` lint checks for
63
+ /// manual `impl` blocks of the `Default` trait of types with default
64
+ /// field values.
64
65
///
65
66
/// ### Example
66
67
///
@@ -114,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
114
115
kind :
115
116
hir:: ItemKind :: Struct ( hir:: VariantData :: Struct { fields, recovered : _ } , _generics) ,
116
117
..
117
- } ) ) => {
118
+ } ) ) if cx . tcx . features ( ) . default_field_values ( ) => {
118
119
let fields_with_default_value: Vec < _ > =
119
120
fields. iter ( ) . filter_map ( |f| f. default ) . collect ( ) ;
120
121
let fields_with_default_impl: Vec < _ > = fields
@@ -133,6 +134,10 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
133
134
_ => None ,
134
135
} )
135
136
. collect ( ) ;
137
+ // FIXME: look at the `Default::default()` implementation and call check_expr and
138
+ // check_const_expr on every field. If all are either of those, then we suggest
139
+ // adding a default field value for the const-able ones and deriving if the feature
140
+ // is enabled.
136
141
if !fields_with_default_value. is_empty ( )
137
142
&& fields. len ( )
138
143
== fields_with_default_value. len ( ) + fields_with_default_impl. len ( )
@@ -512,3 +517,33 @@ fn check_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
512
517
_ => false ,
513
518
}
514
519
}
520
+
521
+
522
+ fn is_const ( cx : & LateContext < ' _ > , def_id : DefId ) -> bool {
523
+ // FIXME: look at the DefKind as well, as things like struct literals and consts are always true
524
+ match cx. tcx . def_kind ( def_id) {
525
+ DefKind :: Ctor ( _, CtorKind :: Fn ) => true
526
+ DefKind :: Fn | DefKind :: AssocFn | DefKind :: Closure => cx. tcx . is_const_fn ( def_id) ,
527
+ _ => false ,
528
+ }
529
+ }
530
+
531
+ fn check_constness ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) -> bool {
532
+ match expr. kind {
533
+ hir:: ExprKind :: Lit ( _) => true ,
534
+ hir:: ExprKind :: Call ( hir:: Expr { kind : hir:: ExprKind :: Path ( path) , hir_id, .. } , fields) => {
535
+ // `field: foo(),` or `field: Ty::assoc(),`
536
+ check_constness ( cx, def_id) && fields. iter ( ) . all ( |f| check_constness ( cx, f) )
537
+ }
538
+ hir:: ExprKind :: Path ( path) => {
539
+ // `field: qualified::Path,` or `field: <Ty as Trait>::Assoc,`
540
+ let res = cx. qpath_res ( & path, hir_id) ;
541
+ let Some ( def_id) = res. opt_def_id ( ) else { return false } ;
542
+ is_const_fn ( cx, def_id)
543
+ }
544
+ hir:: ExprKind :: Struct ( _path, fields, _base) => {
545
+ fields. iter ( ) . all ( |f| check_constness ( cx, f) )
546
+ }
547
+ _ => false ,
548
+ }
549
+ }
0 commit comments