@@ -40,7 +40,7 @@ declare_clippy_lint! {
4040declare_lint_pass ! ( FieldReassignWithDefault => [ FIELD_REASSIGN_WITH_DEFAULT ] ) ;
4141
4242impl LateLintPass < ' _ > for FieldReassignWithDefault {
43- fn check_block ( & mut self , cx : & LateContext < ' _ > , block : & Block < ' _ > ) {
43+ fn check_block < ' tcx > ( & mut self , cx : & LateContext < ' tcx > , block : & Block < ' tcx > ) {
4444 // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
4545 // `default` method of the `Default` trait, and store statement index in current block being
4646 // checked and the name of the bound variable
@@ -68,11 +68,8 @@ impl LateLintPass<'_> for FieldReassignWithDefault {
6868 else if let Some ( ( field_ident, assign_rhs) ) =
6969 field_reassigned_by_stmt ( consecutive_statement, binding_name)
7070 {
71- // extract and store the assigned value for help message
72- let value_snippet = snippet ( cx, assign_rhs. span , ".." ) ;
73-
7471 // always re-insert set value, this way the latest value is stored for output snippet
75- assigned_fields. insert ( field_ident. name , value_snippet ) ;
72+ assigned_fields. insert ( field_ident. name , assign_rhs ) ;
7673
7774 // also set first instance of error for help message
7875 if first_assign. is_none ( ) {
@@ -92,19 +89,33 @@ impl LateLintPass<'_> for FieldReassignWithDefault {
9289 let stmt = & block. stmts [ stmt_idx] ;
9390
9491 if let StmtKind :: Local ( preceding_local) = & stmt. kind {
92+ // filter out fields like `= Default::default()`, because the FRU already covers them
93+ let assigned_fields = assigned_fields
94+ . into_iter ( )
95+ . filter ( |( _, rhs) | !is_expr_default ( rhs, cx) )
96+ . collect :: < FxHashMap < Symbol , & Expr < ' _ > > > ( ) ;
97+
9598 // if all fields of the struct are not assigned, add `.. Default::default()` to the suggestion.
9699 let ext_with_default = !fields_of_type ( binding_type)
97100 . iter ( )
98101 . all ( |field| assigned_fields. contains_key ( & field. name ) ) ;
99102
100103 let field_list = assigned_fields
101104 . into_iter ( )
102- . map ( |( field, value) | format ! ( "{}: {}" , field, value) )
105+ . map ( |( field, rhs) | {
106+ // extract and store the assigned value for help message
107+ let value_snippet = snippet ( cx, rhs. span , ".." ) ;
108+ format ! ( "{}: {}" , field, value_snippet)
109+ } )
103110 . collect :: < Vec < String > > ( )
104111 . join ( ", " ) ;
105112
106113 let sugg = if ext_with_default {
107- format ! ( "{} {{ {}, ..Default::default() }}" , binding_type, field_list)
114+ if field_list. is_empty ( ) {
115+ format ! ( "{}::default()" , binding_type)
116+ } else {
117+ format ! ( "{} {{ {}, ..Default::default() }}" , binding_type, field_list)
118+ }
108119 } else {
109120 format ! ( "{} {{ {} }}" , binding_type, field_list)
110121 } ;
@@ -124,9 +135,28 @@ impl LateLintPass<'_> for FieldReassignWithDefault {
124135 }
125136}
126137
138+ /// Checks if the given expression is the `default` method belonging to the `Default` trait.
139+ fn is_expr_default < ' tcx > ( expr : & ' tcx Expr < ' tcx > , cx : & LateContext < ' tcx > ) -> bool {
140+ if_chain ! {
141+ if let ExprKind :: Call ( ref fn_expr, _) = & expr. kind;
142+ if let ExprKind :: Path ( qpath) = & fn_expr. kind;
143+ if let Res :: Def ( _, def_id) = qpath_res( cx, qpath, fn_expr. hir_id) ;
144+ // right hand side of assignment is `Default::default`
145+ if match_def_path( cx, def_id, & paths:: DEFAULT_TRAIT_METHOD ) ;
146+ then {
147+ true
148+ } else {
149+ false
150+ }
151+ }
152+ }
153+
127154/// Returns the block indices, identifiers and types of bindings set as `Default::default()`, except
128155/// for when the pattern type is a tuple.
129- fn enumerate_bindings_using_default < ' tcx > ( cx : & LateContext < ' tcx > , block : & Block < ' _ > ) -> Vec < ( usize , Symbol , Ty < ' tcx > ) > {
156+ fn enumerate_bindings_using_default < ' tcx > (
157+ cx : & LateContext < ' tcx > ,
158+ block : & Block < ' tcx > ,
159+ ) -> Vec < ( usize , Symbol , Ty < ' tcx > ) > {
130160 block
131161 . stmts
132162 . iter ( )
@@ -142,11 +172,7 @@ fn enumerate_bindings_using_default<'tcx>(cx: &LateContext<'tcx>, block: &Block<
142172 if !matches!( ty. kind( ) , ty:: Tuple ( _) ) ;
143173 // only when assigning `... = Default::default()`
144174 if let Some ( ref expr) = local. init;
145- if let ExprKind :: Call ( ref fn_expr, _) = & expr. kind;
146- if let ExprKind :: Path ( qpath) = & fn_expr. kind;
147- if let Res :: Def ( _, def_id) = qpath_res( cx, qpath, fn_expr. hir_id) ;
148- // right hand side of assignment is `Default::default`
149- if match_def_path( cx, def_id, & paths:: DEFAULT_TRAIT_METHOD ) ;
175+ if is_expr_default( expr, cx) ;
150176 then {
151177 Some ( ( idx, ident. name, ty) )
152178 } else {
0 commit comments