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} ;
2
2
use 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 } ;
6
5
use rustc_span:: symbol:: Symbol ;
7
6
7
+ use rustc_lint:: { LateContext , LateLintPass } ;
8
+ use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
9
+
8
10
declare_clippy_lint ! {
9
11
/// **What it does:** Checks for immediate reassignment of fields initialized
10
12
/// with Default::default().
@@ -13,19 +15,18 @@ declare_clippy_lint! {
13
15
/// T { field: value, ..Default::default() } syntax instead of using a mutable binding.
14
16
///
15
17
/// **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.
21
21
///
22
22
/// **Example:**
23
+ /// Bad:
23
24
/// ```ignore
24
- /// // Bad
25
25
/// let mut a: A = Default::default();
26
26
/// a.i = 42;
27
- ///
28
- /// // Good
27
+ /// ```
28
+ /// Use instead:
29
+ /// ```ignore
29
30
/// let a = A {
30
31
/// i: 42,
31
32
/// .. Default::default()
@@ -38,8 +39,8 @@ declare_clippy_lint! {
38
39
39
40
declare_lint_pass ! ( FieldReassignWithDefault => [ FIELD_REASSIGN_WITH_DEFAULT ] ) ;
40
41
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 < ' _ > ) {
43
44
// store statement index and name of binding for all statements like
44
45
// `let mut binding = Default::default();`
45
46
let binding_statements_using_default: Vec < ( usize , Symbol ) > = block
@@ -51,15 +52,16 @@ impl EarlyLintPass for FieldReassignWithDefault {
51
52
// only take `let ...` statements
52
53
if let StmtKind :: Local ( ref local) = stmt. kind;
53
54
// only take bindings to identifiers
54
- if let PatKind :: Ident ( _, binding , _) = local. pat. kind;
55
+ if let PatKind :: Binding ( _, _ , ident , _) = local. pat. kind;
55
56
// only when assigning `... = Default::default()`
56
57
if let Some ( ref expr) = local. init;
57
58
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) ;
59
61
// 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 ) ;
61
63
then {
62
- Some ( ( idx, binding . name) )
64
+ Some ( ( idx, ident . name) )
63
65
}
64
66
else {
65
67
None
@@ -84,8 +86,8 @@ impl EarlyLintPass for FieldReassignWithDefault {
84
86
// interrupt if the statement is a let binding (`Local`) that shadows the original
85
87
// binding
86
88
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 {
89
91
break ;
90
92
}
91
93
}
@@ -100,7 +102,8 @@ impl EarlyLintPass for FieldReassignWithDefault {
100
102
// only take assignments to fields where the left-hand side field is a field of
101
103
// the same binding as the previous statement
102
104
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;
104
107
if let Some ( second_binding_name) = path. segments. last( ) ;
105
108
if second_binding_name. ident. name == binding_name;
106
109
then {
0 commit comments