1- use crate :: utils:: { match_path_ast , paths, snippet, span_lint_and_note} ;
1+ use crate :: utils:: { match_def_path , paths, qpath_res , snippet, span_lint_and_note} ;
22use if_chain:: if_chain;
3- use rustc_ast:: ast:: { Block , ExprKind , PatKind , StmtKind } ;
4- use rustc_lint:: { EarlyContext , EarlyLintPass } ;
5- use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
3+ use rustc_hir:: def:: Res ;
4+ use rustc_hir:: { Block , ExprKind , PatKind , QPath , StmtKind } ;
65use rustc_span:: symbol:: Symbol ;
76
7+ use rustc_lint:: { LateContext , LateLintPass } ;
8+ use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
9+
810declare_clippy_lint ! {
911 /// **What it does:** Checks for immediate reassignment of fields initialized
1012 /// with Default::default().
@@ -13,19 +15,18 @@ declare_clippy_lint! {
1315 /// T { field: value, ..Default::default() } syntax instead of using a mutable binding.
1416 ///
1517 /// **Known problems:** The lint does not detect calls to Default::default()
16- /// if they are made via another struct implementing the Default trait. This
17- /// may be corrected with a LateLintPass. If type inference stops requiring
18- /// an explicit type for assignment using Default::default() this lint will
19- /// not trigger for cases where the type is elided. This may also be corrected
20- /// with a LateLintPass.
18+ /// if they are made via another struct implementing the Default trait. If type inference stops
19+ /// requiring an explicit type for assignment using Default::default() this lint will not
20+ /// trigger for cases where the type is elided.
2121 ///
2222 /// **Example:**
23+ /// Bad:
2324 /// ```ignore
24- /// // Bad
2525 /// let mut a: A = Default::default();
2626 /// a.i = 42;
27- ///
28- /// // Good
27+ /// ```
28+ /// Use instead:
29+ /// ```ignore
2930 /// let a = A {
3031 /// i: 42,
3132 /// .. Default::default()
@@ -38,8 +39,8 @@ declare_clippy_lint! {
3839
3940declare_lint_pass ! ( FieldReassignWithDefault => [ FIELD_REASSIGN_WITH_DEFAULT ] ) ;
4041
41- impl EarlyLintPass for FieldReassignWithDefault {
42- fn check_block ( & mut self , cx : & EarlyContext < ' _ > , block : & Block ) {
42+ impl LateLintPass < ' _ > for FieldReassignWithDefault {
43+ fn check_block ( & mut self , cx : & LateContext < ' _ > , block : & Block < ' _ > ) {
4344 // store statement index and name of binding for all statements like
4445 // `let mut binding = Default::default();`
4546 let binding_statements_using_default: Vec < ( usize , Symbol ) > = block
@@ -51,15 +52,16 @@ impl EarlyLintPass for FieldReassignWithDefault {
5152 // only take `let ...` statements
5253 if let StmtKind :: Local ( ref local) = stmt. kind;
5354 // only take bindings to identifiers
54- if let PatKind :: Ident ( _, binding , _) = local. pat. kind;
55+ if let PatKind :: Binding ( _, _ , ident , _) = local. pat. kind;
5556 // only when assigning `... = Default::default()`
5657 if let Some ( ref expr) = local. init;
5758 if let ExprKind :: Call ( ref fn_expr, _) = & expr. kind;
58- if let ExprKind :: Path ( _, path ) = & fn_expr. kind;
59+ if let ExprKind :: Path ( qpath ) = & fn_expr. kind;
60+ if let Res :: Def ( _, def_id) = qpath_res( cx, qpath, fn_expr. hir_id) ;
5961 // right hand side of assignment is `Default::default`
60- if match_path_ast ( & path , & paths:: DEFAULT_TRAIT_METHOD ) ;
62+ if match_def_path ( cx , def_id , & paths:: DEFAULT_TRAIT_METHOD ) ;
6163 then {
62- Some ( ( idx, binding . name) )
64+ Some ( ( idx, ident . name) )
6365 }
6466 else {
6567 None
@@ -84,8 +86,8 @@ impl EarlyLintPass for FieldReassignWithDefault {
8486 // interrupt if the statement is a let binding (`Local`) that shadows the original
8587 // binding
8688 if let StmtKind :: Local ( local) = & post_defassign_stmt. kind {
87- if let PatKind :: Ident ( _, id , _) = local. pat . kind {
88- if id . name == binding_name {
89+ if let PatKind :: Binding ( _, _ , ident , _) = local. pat . kind {
90+ if ident . name == binding_name {
8991 break ;
9092 }
9193 }
@@ -100,7 +102,8 @@ impl EarlyLintPass for FieldReassignWithDefault {
100102 // only take assignments to fields where the left-hand side field is a field of
101103 // the same binding as the previous statement
102104 if let ExprKind :: Field ( ref binding, later_field_ident) = assign_lhs. kind;
103- if let ExprKind :: Path ( _, ref path ) = binding. kind;
105+ if let ExprKind :: Path ( ref qpath) = binding. kind;
106+ if let QPath :: Resolved ( _, path) = qpath;
104107 if let Some ( second_binding_name) = path. segments. last( ) ;
105108 if second_binding_name. ident. name == binding_name;
106109 then {
0 commit comments