1
1
use clippy_utils:: {
2
- consts:: constant, diagnostics:: span_lint_and_then, is_from_proc_macro, path_to_local, source:: snippet_opt,
2
+ consts:: { constant, Constant } ,
3
+ diagnostics:: span_lint_and_then,
4
+ is_from_proc_macro, path_to_local,
5
+ source:: snippet_opt,
3
6
} ;
4
7
use rustc_errors:: Applicability ;
5
8
use rustc_hir:: { BinOpKind , Expr , ExprKind } ;
@@ -9,10 +12,11 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
9
12
10
13
declare_clippy_lint ! {
11
14
/// ### What it does
12
- /// Checks for `x == <float>::INFINITY || x == <float>::NEG_INFINITY`.
15
+ /// Checks for manual `is_infinite` reimplementations
16
+ /// (i.e., `x == <float>::INFINITY || x == <float>::NEG_INFINITY`).
13
17
///
14
18
/// ### Why is this bad?
15
- /// This should use the dedicated method instead, `is_infinite`.
19
+ /// This should use the aforementioned dedicated method instead, `is_infinite`.
16
20
///
17
21
/// ### Example
18
22
/// ```rust
@@ -31,20 +35,23 @@ declare_clippy_lint! {
31
35
}
32
36
declare_clippy_lint ! {
33
37
/// ### What it does
34
- /// Checks for `x != <float>::INFINITY && x != <float>::NEG_INFINITY`.
38
+ /// Checks for manual `is_finite` reimplementations
39
+ /// (i.e., `x != <float>::INFINITY && x != <float>::NEG_INFINITY`).
35
40
///
36
41
/// ### Why is this bad?
37
- /// This should use the dedicated method instead, `is_finite`.
42
+ /// This should use the aforementioned dedicated method instead, `is_finite`.
38
43
///
39
44
/// ### Example
40
45
/// ```rust
41
46
/// # let x = 1.0f32;
42
47
/// if x != f32::INFINITY && x != f32::NEG_INFINITY {}
48
+ /// if x.abs() < f32::INFINITY {}
43
49
/// ```
44
50
/// Use instead:
45
51
/// ```rust
46
52
/// # let x = 1.0f32;
47
53
/// if x.is_finite() {}
54
+ /// if x.is_finite() {}
48
55
/// ```
49
56
#[ clippy:: version = "1.72.0" ]
50
57
pub MANUAL_IS_FINITE ,
@@ -84,18 +91,20 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
84
91
&& let ExprKind :: Binary ( rhs_kind, rhs_lhs, rhs_rhs) = rhs. kind
85
92
// Checking all possible scenarios using a function would be a hopeless task, as we have
86
93
// 16 possible alignments of constants/operands. For now, let's use `partition`.
87
- && let ( operands, consts ) = [ lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
94
+ && let ( operands, constants ) = [ lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
88
95
. into_iter ( )
89
96
. partition :: < Vec < & Expr < ' _ > > , _ > ( |i| path_to_local ( i) . is_some ( ) )
90
97
&& let [ first, second] = & * operands
91
- && let Some ( [ const_1, const_2] ) = consts
98
+ && let Some ( [ const_1, const_2] ) = constants
92
99
. into_iter ( )
93
- . map ( |i| constant ( cx, cx. typeck_results ( ) , i) . and_then ( |c| c . to_bits ( ) ) )
100
+ . map ( |i| constant ( cx, cx. typeck_results ( ) , i) )
94
101
. collect :: < Option < Vec < _ > > > ( )
95
102
. as_deref ( )
96
103
&& path_to_local ( first) . is_some_and ( |f| path_to_local ( second) . is_some_and ( |s| f == s) )
97
- && ( is_infinity ( * const_1) && is_neg_infinity ( * const_2)
98
- || is_neg_infinity ( * const_1) && is_infinity ( * const_2) )
104
+ // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
105
+ // case somebody does that for some reason
106
+ && ( is_infinity ( const_1) && is_neg_infinity ( const_2)
107
+ || is_neg_infinity ( const_1) && is_infinity ( const_2) )
99
108
&& let Some ( local_snippet) = snippet_opt ( cx, first. span )
100
109
&& !is_from_proc_macro ( cx, expr)
101
110
{
@@ -141,18 +150,26 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
141
150
format ! ( "!{local_snippet}.is_infinite()" ) ,
142
151
Applicability :: MaybeIncorrect ,
143
152
) ;
144
- }
153
+ } ,
145
154
}
146
- }
155
+ } ,
147
156
) ;
148
157
}
149
158
}
150
159
}
151
160
152
- fn is_infinity ( bits : u128 ) -> bool {
153
- bits == 0x7f80_0000 || bits == 0x7ff0_0000_0000_0000
161
+ fn is_infinity ( constant : & Constant < ' _ > ) -> bool {
162
+ match constant {
163
+ Constant :: F32 ( float) => * float == f32:: INFINITY ,
164
+ Constant :: F64 ( float) => * float == f64:: INFINITY ,
165
+ _ => false ,
166
+ }
154
167
}
155
168
156
- fn is_neg_infinity ( bits : u128 ) -> bool {
157
- bits == 0xff80_0000 || bits == 0xfff0_0000_0000_0000
169
+ fn is_neg_infinity ( constant : & Constant < ' _ > ) -> bool {
170
+ match constant {
171
+ Constant :: F32 ( float) => * float == f32:: NEG_INFINITY ,
172
+ Constant :: F64 ( float) => * float == f64:: NEG_INFINITY ,
173
+ _ => false ,
174
+ }
158
175
}
0 commit comments