@@ -3,10 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
33use clippy_utils:: source:: snippet_with_applicability;
44use clippy_utils:: { clip, peel_hir_expr_refs, unsext} ;
55use rustc_errors:: Applicability ;
6- use rustc_hir:: { BinOpKind , Expr , ExprKind , Node } ;
6+ use rustc_hir:: { BinOpKind , Expr , ExprKind , HirId , Item , ItemKind , Node , QPath } ;
77use rustc_lint:: LateContext ;
88use rustc_middle:: ty;
9- use rustc_span:: Span ;
9+ use rustc_span:: { Span , sym } ;
1010
1111use super :: IDENTITY_OP ;
1212
@@ -17,7 +17,7 @@ pub(crate) fn check<'tcx>(
1717 left : & ' tcx Expr < ' _ > ,
1818 right : & ' tcx Expr < ' _ > ,
1919) {
20- if !is_allowed ( cx, op, left, right) {
20+ if !is_allowed ( cx, expr , op, left, right) {
2121 return ;
2222 }
2323
@@ -165,7 +165,14 @@ fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, child: &Expr<'_>)
165165 Parens :: Needed
166166}
167167
168- fn is_allowed ( cx : & LateContext < ' _ > , cmp : BinOpKind , left : & Expr < ' _ > , right : & Expr < ' _ > ) -> bool {
168+ fn is_allowed ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , cmp : BinOpKind , left : & Expr < ' _ > , right : & Expr < ' _ > ) -> bool {
169+ // Exclude case where the left or right side is a call to `Default::default()`
170+ // and the expression is not a let binding's init expression and the let binding has a type
171+ // annotation, or a function's return value.
172+ if ( is_default_call ( cx, left) || is_default_call ( cx, right) ) && !is_expr_with_type_annotation ( cx, expr. hir_id ) {
173+ return false ;
174+ }
175+
169176 // This lint applies to integers and their references
170177 cx. typeck_results ( ) . expr_ty ( left) . peel_refs ( ) . is_integral ( )
171178 && cx. typeck_results ( ) . expr_ty ( right) . peel_refs ( ) . is_integral ( )
@@ -175,6 +182,20 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Exp
175182 && ConstEvalCtxt :: new ( cx) . eval_simple ( left) == Some ( Constant :: Int ( 1 ) ) )
176183}
177184
185+ /// Check if the expression is a call to `Default::default()`
186+ fn is_default_call ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
187+ if let ExprKind :: Call ( func, [ ] ) = peel_hir_expr_refs ( expr) . 0 . kind
188+ && let ExprKind :: Path ( qpath) = func. kind
189+ // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
190+ && let QPath :: Resolved ( None , _path) = qpath
191+ && let Some ( def_id) = cx. qpath_res ( & qpath, func. hir_id ) . opt_def_id ( )
192+ && cx. tcx . is_diagnostic_item ( sym:: default_fn, def_id)
193+ {
194+ return true ;
195+ }
196+ false
197+ }
198+
178199fn check_remainder ( cx : & LateContext < ' _ > , left : & Expr < ' _ > , right : & Expr < ' _ > , span : Span , arg : Span ) {
179200 let ecx = ConstEvalCtxt :: new ( cx) ;
180201 if match ( ecx. eval_full_int ( left) , ecx. eval_full_int ( right) ) {
@@ -234,3 +255,39 @@ fn span_ineffective_operation(
234255 applicability,
235256 ) ;
236257}
258+
259+ /// Check if the expression is a let binding's init expression and the let binding has a type
260+ /// annotation. Also check if the expression is a function's return value.
261+ fn is_expr_with_type_annotation ( cx : & LateContext < ' _ > , hir_id : HirId ) -> bool {
262+ // Get the parent node of the expression
263+ if let Some ( ( _, parent) ) = cx. tcx . hir_parent_iter ( hir_id) . next ( ) {
264+ match parent {
265+ Node :: LetStmt ( local) => {
266+ // Check if this expression is the init expression of the let binding
267+ if let Some ( init) = local. init
268+ && init. hir_id == hir_id
269+ {
270+ // Check if the let binding has an explicit type annotation
271+ return local. ty . is_some ( ) ;
272+ }
273+ } ,
274+ Node :: Block ( block) => {
275+ // If the parent node is a block, we can make sure the expression is the last expression in the
276+ // block.
277+ return is_expr_with_type_annotation ( cx, block. hir_id ) ;
278+ } ,
279+ Node :: Expr ( expr) => {
280+ return is_expr_with_type_annotation ( cx, expr. hir_id ) ;
281+ } ,
282+ Node :: Item ( Item {
283+ kind : ItemKind :: Fn { .. } ,
284+ ..
285+ } ) => {
286+ // Every function has a return type, so we can return true.
287+ return true ;
288+ } ,
289+ _ => { } ,
290+ }
291+ }
292+ false
293+ }
0 commit comments