1
- use crate :: utils:: span_lint_and_note;
1
+ use crate :: utils:: { snippet , span_lint_and_note} ;
2
2
use if_chain:: if_chain;
3
- use rustc_ast_pretty :: pprust :: { expr_to_string , ty_to_string } ;
3
+ use rustc_ast :: ast :: { BindingMode , Block , ExprKind , Mutability , PatKind , StmtKind } ;
4
4
use rustc_lint:: { EarlyContext , EarlyLintPass } ;
5
5
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
6
6
use rustc_span:: symbol:: Symbol ;
7
- use syntax:: ast:: { BindingMode , Block , ExprKind , Mutability , PatKind , StmtKind } ;
8
7
9
8
declare_clippy_lint ! {
10
9
/// **What it does:** Checks for immediate reassignment of fields initialized
@@ -39,6 +38,10 @@ declare_clippy_lint! {
39
38
40
39
declare_lint_pass ! ( FieldReassignWithDefault => [ FIELD_REASSIGN_WITH_DEFAULT ] ) ;
41
40
41
+ /// The token for the Default -trait.
42
+ const DEFAULT_TRAIT_TOKEN : & str = "Default" ;
43
+ const DEFAULT_FUNC_TOKEN : & str = "default" ;
44
+
42
45
impl EarlyLintPass for FieldReassignWithDefault {
43
46
fn check_block ( & mut self , cx : & EarlyContext < ' _ > , block : & Block ) {
44
47
// store statement index and name of binding for all statements like
@@ -49,17 +52,18 @@ impl EarlyLintPass for FieldReassignWithDefault {
49
52
. enumerate ( )
50
53
. filter_map ( |( idx, stmt) | {
51
54
if_chain ! {
52
- // only take `let ...`
55
+ // only take `let ...` statements
53
56
if let StmtKind :: Local ( ref local) = stmt. kind;
54
- // only take `... mut < binding> ...`
57
+ // only take `... mut binding ...`
55
58
if let PatKind :: Ident ( BindingMode :: ByValue ( Mutability :: Mut ) , binding, _) = local. pat. kind;
56
59
// only when assigning `... = Default::default()`
57
60
if let Some ( ref expr) = local. init;
58
61
if let ExprKind :: Call ( ref fn_expr, _) = & expr. kind;
59
- if let ExprKind :: Path ( _, path) = & fn_expr. kind;
62
+ if let ExprKind :: Path ( _, path ) = & fn_expr. kind;
60
63
if path. segments. len( ) >= 2 ;
61
- if path. segments[ path. segments. len( ) -2 ] . ident. as_str( ) == "Default" ;
62
- if path. segments. last( ) . unwrap( ) . ident. as_str( ) == "default" ;
64
+ // right hand side of assignment is `Default::default`
65
+ if path. segments[ path. segments. len( ) -2 ] . ident. to_string( ) == DEFAULT_TRAIT_TOKEN ;
66
+ if path. segments. last( ) . unwrap( ) . ident. to_string( ) == DEFAULT_FUNC_TOKEN ;
63
67
then {
64
68
Some ( ( idx, binding. name) )
65
69
}
@@ -87,7 +91,7 @@ impl EarlyLintPass for FieldReassignWithDefault {
87
91
if let ExprKind :: Assign ( ref later_lhs, ref later_rhs, _) = later_expr. kind;
88
92
// only take assignments to fields where the field refers to the same binding as the previous statement
89
93
if let ExprKind :: Field ( ref binding_name_candidate, later_field_ident) = later_lhs. kind;
90
- if let ExprKind :: Path ( _, path) = & binding_name_candidate. kind;
94
+ if let ExprKind :: Path ( _, ref path ) = binding_name_candidate. kind;
91
95
if let Some ( second_binding_name) = path. segments. last( ) ;
92
96
if second_binding_name. ident. name == binding_name;
93
97
then {
@@ -96,17 +100,17 @@ impl EarlyLintPass for FieldReassignWithDefault {
96
100
if let StmtKind :: Local ( preceding_local) = & stmt. kind {
97
101
// reorganize the latter assigment statement into `field` and `value` for the lint
98
102
let field = later_field_ident. name. as_str( ) ;
99
- let value = expr_to_string ( later_rhs) ;
103
+ let value_snippet = snippet ( cx , later_rhs. span , ".." ) ;
100
104
if let Some ( ty) = & preceding_local. ty {
101
- let ty = ty_to_string ( ty ) ;
105
+ let ty_snippet = snippet ( cx , ty . span , "_" ) ;
102
106
103
107
span_lint_and_note(
104
108
cx,
105
109
FIELD_REASSIGN_WITH_DEFAULT ,
106
110
later_stmt. span,
107
111
"field assignment outside of initializer for an instance created with Default::default()" ,
108
- preceding_local. span,
109
- & format!( "consider initializing the variable immutably with `{} {{ {}: {}, ..Default::default() }}`" , ty , field, value ) ,
112
+ Some ( preceding_local. span) ,
113
+ & format!( "consider initializing the variable immutably with `{} {{ {}: {}, ..Default::default() }}`" , ty_snippet , field, value_snippet ) ,
110
114
) ;
111
115
}
112
116
}
0 commit comments