1- use crate :: utils:: { contains_name, match_def_path, paths, qpath_res, snippet, span_lint_and_note} ;
1+ use crate :: utils:: { any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet} ;
2+ use crate :: utils:: { span_lint_and_note, span_lint_and_sugg} ;
23use if_chain:: if_chain;
4+ use rustc_data_structures:: fx:: FxHashSet ;
5+ use rustc_errors:: Applicability ;
36use rustc_hir:: def:: Res ;
47use rustc_hir:: { Block , Expr , ExprKind , PatKind , QPath , Stmt , StmtKind } ;
8+ use rustc_lint:: { LateContext , LateLintPass } ;
59use rustc_middle:: ty:: { self , Adt , Ty } ;
10+ use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
611use rustc_span:: symbol:: { Ident , Symbol } ;
12+ use rustc_span:: Span ;
713
8- use rustc_lint:: { LateContext , LateLintPass } ;
9- use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
14+ declare_clippy_lint ! {
15+ /// **What it does:** Checks for literal calls to `Default::default()`.
16+ ///
17+ /// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is
18+ /// being gotten than the generic `Default`.
19+ ///
20+ /// **Known problems:** None.
21+ ///
22+ /// **Example:**
23+ /// ```rust
24+ /// // Bad
25+ /// let s: String = Default::default();
26+ ///
27+ /// // Good
28+ /// let s = String::default();
29+ /// ```
30+ pub DEFAULT_TRAIT_ACCESS ,
31+ pedantic,
32+ "checks for literal calls to `Default::default()`"
33+ }
1034
1135declare_clippy_lint ! {
1236 /// **What it does:** Checks for immediate reassignment of fields initialized
@@ -19,12 +43,14 @@ declare_clippy_lint! {
1943 /// **Example:**
2044 /// Bad:
2145 /// ```
46+ /// # #[derive(Default)]
2247 /// # struct A { i: i32 }
2348 /// let mut a: A = Default::default();
2449 /// a.i = 42;
2550 /// ```
2651 /// Use instead:
2752 /// ```
53+ /// # #[derive(Default)]
2854 /// # struct A { i: i32 }
2955 /// let a = A {
3056 /// i: 42,
@@ -36,9 +62,46 @@ declare_clippy_lint! {
3662 "binding initialized with Default should have its fields set in the initializer"
3763}
3864
39- declare_lint_pass ! ( FieldReassignWithDefault => [ FIELD_REASSIGN_WITH_DEFAULT ] ) ;
65+ #[ derive( Default ) ]
66+ pub struct DefaultPass {
67+ // Spans linted by `field_reassign_with_default`.
68+ reassigned_linted : FxHashSet < Span > ,
69+ }
70+
71+ impl_lint_pass ! ( DefaultPass => [ DEFAULT_TRAIT_ACCESS , FIELD_REASSIGN_WITH_DEFAULT ] ) ;
72+
73+ impl LateLintPass < ' _ > for DefaultPass {
74+ fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
75+ if_chain ! {
76+ // Avoid cases already linted by `field_reassign_with_default`
77+ if !self . reassigned_linted. contains( & expr. span) ;
78+ if let ExprKind :: Call ( ref path, ..) = expr. kind;
79+ if !any_parent_is_automatically_derived( cx. tcx, expr. hir_id) ;
80+ if let ExprKind :: Path ( ref qpath) = path. kind;
81+ if let Some ( def_id) = cx. qpath_res( qpath, path. hir_id) . opt_def_id( ) ;
82+ if match_def_path( cx, def_id, & paths:: DEFAULT_TRAIT_METHOD ) ;
83+ // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
84+ if let QPath :: Resolved ( None , _path) = qpath;
85+ then {
86+ let expr_ty = cx. typeck_results( ) . expr_ty( expr) ;
87+ if let ty:: Adt ( def, ..) = expr_ty. kind( ) {
88+ // TODO: Work out a way to put "whatever the imported way of referencing
89+ // this type in this file" rather than a fully-qualified type.
90+ let replacement = format!( "{}::default()" , cx. tcx. def_path_str( def. did) ) ;
91+ span_lint_and_sugg(
92+ cx,
93+ DEFAULT_TRAIT_ACCESS ,
94+ expr. span,
95+ & format!( "calling `{}` is more clear than this expression" , replacement) ,
96+ "try" ,
97+ replacement,
98+ Applicability :: Unspecified , // First resolve the TODO above
99+ ) ;
100+ }
101+ }
102+ }
103+ }
40104
41- impl LateLintPass < ' _ > for FieldReassignWithDefault {
42105 fn check_block < ' tcx > ( & mut self , cx : & LateContext < ' tcx > , block : & Block < ' tcx > ) {
43106 // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
44107 // `default` method of the `Default` trait, and store statement index in current block being
@@ -47,7 +110,7 @@ impl LateLintPass<'_> for FieldReassignWithDefault {
47110
48111 // start from the `let mut _ = _::default();` and look at all the following
49112 // statements, see if they re-assign the fields of the binding
50- for ( stmt_idx, binding_name, binding_type) in binding_statements_using_default {
113+ for ( stmt_idx, binding_name, binding_type, span ) in binding_statements_using_default {
51114 // the last statement of a block cannot trigger the lint
52115 if stmt_idx == block. stmts . len ( ) - 1 {
53116 break ;
@@ -145,6 +208,7 @@ impl LateLintPass<'_> for FieldReassignWithDefault {
145208 sugg
146209 ) ,
147210 ) ;
211+ self . reassigned_linted . insert ( span) ;
148212 }
149213 }
150214 }
@@ -171,7 +235,7 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool
171235fn enumerate_bindings_using_default < ' tcx > (
172236 cx : & LateContext < ' tcx > ,
173237 block : & Block < ' tcx > ,
174- ) -> Vec < ( usize , Symbol , Ty < ' tcx > ) > {
238+ ) -> Vec < ( usize , Symbol , Ty < ' tcx > , Span ) > {
175239 block
176240 . stmts
177241 . iter ( )
@@ -189,7 +253,7 @@ fn enumerate_bindings_using_default<'tcx>(
189253 if let Some ( ref expr) = local. init;
190254 if is_expr_default( expr, cx) ;
191255 then {
192- Some ( ( idx, ident. name, ty) )
256+ Some ( ( idx, ident. name, ty, expr . span ) )
193257 } else {
194258 None
195259 }
0 commit comments