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 } ;
22use 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 } ;
96use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
10- use rustc_span:: symbol:: kw;
7+ use rustc_span:: sym;
8+ use std:: borrow:: Cow ;
119
1210declare_clippy_lint ! {
1311 /// ### What it does
@@ -33,12 +31,9 @@ declare_lint_pass!(TrivialDefaultConstructedTypes => [TRIVIAL_DEFAULT_CONSTRUCTE
3331
3432impl < ' tcx > LateLintPass < ' tcx > for TrivialDefaultConstructedTypes {
3533 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 ( )
3735 && 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 )
4237 {
4338 let ret_ty = cx
4439 . typeck_results ( )
@@ -58,14 +53,15 @@ impl<'tcx> LateLintPass<'tcx> for TrivialDefaultConstructedTypes {
5853 Applicability :: MachineApplicable ,
5954 ) ;
6055 } else if let ty:: Tuple ( fields) = ret_ty. kind ( )
56+ && fields. len ( ) <= 3
6157 && let Some ( fields_default) = fields. iter ( )
6258 . map ( |field| default_value ( cx, field) )
63- . collect :: < Option < Vec < & ' static str > > > ( )
59+ . collect :: < Option < Vec < _ > > > ( )
6460 && !is_from_proc_macro ( cx, expr)
6561 {
66- let default = if fields . len ( ) == 1 {
62+ let default = if let [ default ] = & * fields_default {
6763 // Needs trailing comma to be a single-element tuple
68- fields_default [ 0 ] . to_owned ( ) + ","
64+ format ! ( "{default}," )
6965 } else {
7066 fields_default. join ( ", " )
7167 } ;
@@ -101,19 +97,16 @@ impl<'tcx> LateLintPass<'tcx> for TrivialDefaultConstructedTypes {
10197}
10298
10399/// 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 > > {
105101 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 ( ) )
112104 } ,
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 ( ) ) ,
117110 // Do not handle `ty::Char`, it's a lot less readable
118111 _ => None ,
119112 }
0 commit comments