1
- use rustc_hir:: { BinOpKind , Expr , ExprKind } ;
1
+ use rustc_hir:: { BinOpKind , Expr , ExprKind , QPath } ;
2
2
use rustc_lint:: LateContext ;
3
3
use rustc_middle:: ty;
4
4
@@ -7,7 +7,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant};
7
7
use clippy_utils:: diagnostics:: span_lint_and_help;
8
8
use clippy_utils:: source:: snippet;
9
9
use clippy_utils:: ty:: is_isize_or_usize;
10
- use clippy_utils:: { clip, int_bits, unsext} ;
10
+ use clippy_utils:: { clip, int_bits, sym , unsext} ;
11
11
12
12
use super :: ABSURD_EXTREME_COMPARISONS ;
13
13
@@ -121,6 +121,78 @@ fn detect_absurd_comparison<'tcx>(
121
121
fn detect_extreme_expr < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) -> Option < ExtremeExpr < ' tcx > > {
122
122
let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
123
123
124
+ // Detect Duration zero values
125
+ if let ty:: Adt ( adt_def, _) = * ty. kind ( )
126
+ && cx. tcx . is_diagnostic_item ( sym:: Duration , adt_def. did ( ) )
127
+ {
128
+ if let ExprKind :: Call ( func, args) = & expr. kind {
129
+ if let ExprKind :: Path ( qpath) = & func. kind {
130
+ let method_name = match qpath {
131
+ QPath :: Resolved ( _, path) => path. segments . last ( ) . map ( |seg| seg. ident . name . as_str ( ) ) ,
132
+ QPath :: TypeRelative ( _, seg) => Some ( seg. ident . name . as_str ( ) ) ,
133
+ _ => None ,
134
+ } ;
135
+
136
+ // Handle constructors like from_secs(0), from_millis(0), etc.
137
+ if args. len ( ) == 1 {
138
+ let int_methods = [ "from_secs" , "from_millis" , "from_micros" , "from_nanos" ] ;
139
+ if int_methods. iter ( ) . any ( |& m| Some ( m) == method_name) {
140
+ if let Some ( Constant :: Int ( 0 ) ) = ConstEvalCtxt :: new ( cx) . eval ( & args[ 0 ] ) {
141
+ return Some ( ExtremeExpr {
142
+ which : ExtremeType :: Minimum ,
143
+ expr,
144
+ } ) ;
145
+ }
146
+ }
147
+
148
+ // Handle float constructors
149
+ let float_methods = [ "from_secs_f32" , "from_secs_f64" ] ;
150
+ if float_methods. iter ( ) . any ( |& m| Some ( m) == method_name) {
151
+ if let ExprKind :: Lit ( lit) = & args[ 0 ] . kind {
152
+ let lit_str = snippet ( cx, lit. span , "" ) ;
153
+ if lit_str == "0.0" || lit_str == "0" {
154
+ return Some ( ExtremeExpr {
155
+ which : ExtremeType :: Minimum ,
156
+ expr,
157
+ } ) ;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ // Handle new(0, 0)
163
+ else if args. len ( ) == 2 && method_name == Some ( "new" ) {
164
+ let first_arg_const = ConstEvalCtxt :: new ( cx) . eval ( & args[ 0 ] ) ;
165
+ let second_arg_const = ConstEvalCtxt :: new ( cx) . eval ( & args[ 1 ] ) ;
166
+
167
+ if let ( Some ( Constant :: Int ( 0 ) ) , Some ( Constant :: Int ( 0 ) ) ) = ( first_arg_const, second_arg_const) {
168
+ return Some ( ExtremeExpr {
169
+ which : ExtremeType :: Minimum ,
170
+ expr,
171
+ } ) ;
172
+ }
173
+
174
+ if let ( ExprKind :: Path ( _) , ExprKind :: Path ( _) ) = ( & args[ 0 ] . kind , & args[ 1 ] . kind ) {
175
+ if snippet ( cx, args[ 0 ] . span , "" ) . contains ( "zero" )
176
+ && snippet ( cx, args[ 1 ] . span , "" ) . contains ( "zero" )
177
+ {
178
+ return Some ( ExtremeExpr {
179
+ which : ExtremeType :: Minimum ,
180
+ expr,
181
+ } ) ;
182
+ }
183
+ }
184
+ }
185
+ // 0-arg constructor: default()
186
+ else if args. is_empty ( ) && method_name == Some ( "default" ) {
187
+ return Some ( ExtremeExpr {
188
+ which : ExtremeType :: Minimum ,
189
+ expr,
190
+ } ) ;
191
+ }
192
+ }
193
+ }
194
+ }
195
+
124
196
let cv = ConstEvalCtxt :: new ( cx) . eval ( expr) ?;
125
197
126
198
let which = match ( ty. kind ( ) , cv) {
0 commit comments