11use clippy_utils:: diagnostics:: span_lint_and_sugg;
22use clippy_utils:: macros:: macro_backtrace;
3- use clippy_utils:: source:: snippet_opt;
43use clippy_utils:: ty:: expr_sig;
54use clippy_utils:: { is_default_equivalent, path_def_id} ;
65use rustc_errors:: Applicability ;
@@ -9,20 +8,16 @@ use rustc_hir::intravisit::{walk_ty, Visitor};
98use rustc_hir:: { Block , Expr , ExprKind , Local , Node , QPath , Ty , TyKind } ;
109use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1110use rustc_middle:: lint:: in_external_macro;
12- use rustc_middle:: ty:: print:: with_forced_trimmed_paths;
13- use rustc_middle:: ty:: IsSuggestable ;
1411use rustc_session:: declare_lint_pass;
1512use rustc_span:: sym;
1613
1714declare_clippy_lint ! {
1815 /// ### What it does
19- /// checks for `Box::new(T ::default())`, which is better written as
20- /// `Box::<T>:: default()`.
16+ /// checks for `Box::new(Default ::default())`, which can be written as
17+ /// `Box::default()`.
2118 ///
2219 /// ### Why is this bad?
23- /// First, it's more complex, involving two calls instead of one.
24- /// Second, `Box::default()` can be faster
25- /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
20+ /// `Box::default()` is equivalent and more concise.
2621 ///
2722 /// ### Example
2823 /// ```no_run
@@ -34,7 +29,7 @@ declare_clippy_lint! {
3429 /// ```
3530 #[ clippy:: version = "1.66.0" ]
3631 pub BOX_DEFAULT ,
37- perf ,
32+ style ,
3833 "Using Box::new(T::default()) instead of Box::default()"
3934}
4035
@@ -53,38 +48,22 @@ impl LateLintPass<'_> for BoxDefault {
5348 && path_def_id ( cx, ty) . map_or ( false , |id| Some ( id) == cx. tcx . lang_items ( ) . owned_box ( ) )
5449 // And the single argument to the call is another function call
5550 // This is the `T::default()` of `Box::new(T::default())`
56- && let ExprKind :: Call ( arg_path, inner_call_args ) = arg. kind
51+ && let ExprKind :: Call ( arg_path, _ ) = arg. kind
5752 // And we are not in a foreign crate's macro
5853 && !in_external_macro ( cx. sess ( ) , expr. span )
5954 // And the argument expression has the same context as the outer call expression
6055 // or that we are inside a `vec!` macro expansion
6156 && ( expr. span . eq_ctxt ( arg. span ) || is_local_vec_expn ( cx, arg, expr) )
62- // And the argument is equivalent to `Default::default()`
63- && is_default_equivalent ( cx, arg)
57+ // And the argument is `Default::default()` or the type is specified
58+ && ( is_plain_default ( cx , arg_path ) || ( given_type ( cx , expr ) && is_default_equivalent ( cx, arg) ) )
6459 {
6560 span_lint_and_sugg (
6661 cx,
6762 BOX_DEFAULT ,
6863 expr. span ,
6964 "`Box::new(_)` of default value" ,
7065 "try" ,
71- if is_plain_default ( cx, arg_path) || given_type ( cx, expr) {
72- "Box::default()" . into ( )
73- } else if let Some ( arg_ty) = cx. typeck_results ( ) . expr_ty ( arg) . make_suggestable ( cx. tcx , true ) {
74- // Check if we can copy from the source expression in the replacement.
75- // We need the call to have no argument (see `explicit_default_type`).
76- if inner_call_args. is_empty ( )
77- && let Some ( ty) = explicit_default_type ( arg_path)
78- && let Some ( s) = snippet_opt ( cx, ty. span )
79- {
80- format ! ( "Box::<{s}>::default()" )
81- } else {
82- // Otherwise, use the inferred type's formatting.
83- with_forced_trimmed_paths ! ( format!( "Box::<{arg_ty}>::default()" ) )
84- }
85- } else {
86- return ;
87- } ,
66+ "Box::default()" . into ( ) ,
8867 Applicability :: MachineApplicable ,
8968 ) ;
9069 }
@@ -103,20 +82,6 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool {
10382 }
10483}
10584
106- // Checks whether the call is of the form `A::B::f()`. Returns `A::B` if it is.
107- //
108- // In the event we have this kind of construct, it's easy to use `A::B` as a replacement in the
109- // quickfix. `f` must however have no parameter. Should `f` have some, then some of the type of
110- // `A::B` may be inferred from the arguments. This would be the case for `Vec::from([0; false])`,
111- // where the argument to `from` allows inferring this is a `Vec<bool>`
112- fn explicit_default_type < ' a > ( arg_path : & ' a Expr < ' _ > ) -> Option < & ' a Ty < ' a > > {
113- if let ExprKind :: Path ( QPath :: TypeRelative ( ty, _) ) = & arg_path. kind {
114- Some ( ty)
115- } else {
116- None
117- }
118- }
119-
12085fn is_local_vec_expn ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , ref_expr : & Expr < ' _ > ) -> bool {
12186 macro_backtrace ( expr. span ) . next ( ) . map_or ( false , |call| {
12287 cx. tcx . is_diagnostic_item ( sym:: vec_macro, call. def_id ) && call. span . eq_ctxt ( ref_expr. span )
0 commit comments