1
- use clippy_utils:: { diagnostics:: span_lint_and_sugg, is_from_proc_macro, is_lang_item_or_ctor, last_path_segment } ;
1
+ use clippy_utils:: { diagnostics:: span_lint_and_sugg, is_from_proc_macro, is_lang_item_or_ctor, is_trait_item } ;
2
2
use rustc_errors:: Applicability ;
3
- use rustc_hir:: { Expr , ExprKind , LangItem , QPath } ;
4
- use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
5
- use rustc_middle:: {
6
- lint:: in_external_macro,
7
- ty:: { self , Ty } ,
8
- } ;
3
+ use rustc_hir:: { Expr , ExprKind , LangItem } ;
4
+ use rustc_lint:: { LateContext , LateLintPass } ;
5
+ use rustc_middle:: ty:: { self , Ty } ;
9
6
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
10
- use rustc_span:: symbol:: kw;
7
+ use rustc_span:: sym;
8
+ use std:: borrow:: Cow ;
11
9
12
10
declare_clippy_lint ! {
13
11
/// ### What it does
@@ -33,12 +31,9 @@ declare_lint_pass!(TrivialDefaultConstructedTypes => [TRIVIAL_DEFAULT_CONSTRUCTE
33
31
34
32
impl < ' tcx > LateLintPass < ' tcx > for TrivialDefaultConstructedTypes {
35
33
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) {
36
- if !in_external_macro ( cx . sess ( ) , expr. span )
34
+ if !expr. span . from_expansion ( )
37
35
&& let ExprKind :: Call ( call, _) = expr. kind
38
- && let ExprKind :: Path ( qpath) = call. kind
39
- // `last_path_segment` ICEs if we give it a `LangItem`.
40
- && !matches ! ( qpath, QPath :: LangItem ( ..) )
41
- && last_path_segment ( & qpath) . ident . name == kw:: Default
36
+ && is_trait_item ( cx, call, sym:: Default )
42
37
{
43
38
let ret_ty = cx
44
39
. typeck_results ( )
@@ -58,14 +53,15 @@ impl<'tcx> LateLintPass<'tcx> for TrivialDefaultConstructedTypes {
58
53
Applicability :: MachineApplicable ,
59
54
) ;
60
55
} else if let ty:: Tuple ( fields) = ret_ty. kind ( )
56
+ && fields. len ( ) <= 3
61
57
&& let Some ( fields_default) = fields. iter ( )
62
58
. map ( |field| default_value ( cx, field) )
63
- . collect :: < Option < Vec < & ' static str > > > ( )
59
+ . collect :: < Option < Vec < _ > > > ( )
64
60
&& !is_from_proc_macro ( cx, expr)
65
61
{
66
- let default = if fields . len ( ) == 1 {
62
+ let default = if let [ default ] = & * fields_default {
67
63
// Needs trailing comma to be a single-element tuple
68
- fields_default [ 0 ] . to_owned ( ) + ","
64
+ format ! ( "{default}," )
69
65
} else {
70
66
fields_default. join ( ", " )
71
67
} ;
@@ -101,19 +97,16 @@ impl<'tcx> LateLintPass<'tcx> for TrivialDefaultConstructedTypes {
101
97
}
102
98
103
99
/// Gets the default value of `ty`.
104
- fn default_value ( cx : & LateContext < ' _ > , ty : Ty < ' _ > ) -> Option < & ' static str > {
100
+ fn default_value ( cx : & LateContext < ' _ > , ty : Ty < ' _ > ) -> Option < Cow < ' static , str > > {
105
101
match ty. kind ( ) {
106
- ty:: Adt ( def, _) => {
107
- if is_lang_item_or_ctor ( cx, def. did ( ) , LangItem :: Option ) {
108
- return Some ( "None" ) ;
109
- }
110
-
111
- None
102
+ ty:: Adt ( def, substs) if let [ subst] = substs. as_slice ( ) => {
103
+ is_lang_item_or_ctor ( cx, def. did ( ) , LangItem :: Option ) . then ( || format ! ( "None::<{subst}>" ) . into ( ) )
112
104
} ,
113
- ty:: Bool => Some ( "false" ) ,
114
- ty:: Str => Some ( r#""""# ) ,
115
- ty:: Int ( _) | ty:: Uint ( _) => Some ( "0" ) ,
116
- ty:: Float ( _) => Some ( "0.0" ) ,
105
+ ty:: Bool => Some ( "false" . into ( ) ) ,
106
+ ty:: Str => Some ( r#""""# . into ( ) ) ,
107
+ ty:: Int ( suffix) => Some ( format ! ( "0{}" , suffix. name_str( ) ) . into ( ) ) ,
108
+ ty:: Uint ( suffix) => Some ( format ! ( "0{}" , suffix. name_str( ) ) . into ( ) ) ,
109
+ ty:: Float ( suffix) => Some ( format ! ( "0.0{}" , suffix. name_str( ) ) . into ( ) ) ,
117
110
// Do not handle `ty::Char`, it's a lot less readable
118
111
_ => None ,
119
112
}
0 commit comments