@@ -20,8 +20,8 @@ declare_lint! {
2020 /// }
2121 ///
2222 /// #[deny(default_could_be_derived)]
23- /// impl Default for Foo {
24- /// fn default() -> Foo {
23+ /// impl Default for A {
24+ /// fn default() -> A {
2525 /// A {
2626 /// b: None,
2727 /// }
@@ -59,8 +59,9 @@ declare_lint! {
5959}
6060
6161declare_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.
6465 ///
6566 /// ### Example
6667 ///
@@ -114,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
114115 kind :
115116 hir:: ItemKind :: Struct ( hir:: VariantData :: Struct { fields, recovered : _ } , _generics) ,
116117 ..
117- } ) ) => {
118+ } ) ) if cx . tcx . features ( ) . default_field_values ( ) => {
118119 let fields_with_default_value: Vec < _ > =
119120 fields. iter ( ) . filter_map ( |f| f. default ) . collect ( ) ;
120121 let fields_with_default_impl: Vec < _ > = fields
@@ -133,6 +134,10 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
133134 _ => None ,
134135 } )
135136 . 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.
136141 if !fields_with_default_value. is_empty ( )
137142 && fields. len ( )
138143 == fields_with_default_value. len ( ) + fields_with_default_impl. len ( )
@@ -512,3 +517,33 @@ fn check_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
512517 _ => false ,
513518 }
514519}
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