11use rustc_errors:: Applicability ;
2- use rustc_hir:: { Expr , ExprKind } ;
3- use rustc_lint:: { LateContext , LateLintPass } ;
2+ use rustc_hir:: { BinOpKind , Expr , ExprKind } ;
3+ use rustc_lint:: LateContext ;
44use rustc_middle:: ty:: layout:: LayoutOf ;
55use rustc_middle:: ty:: { self , IntTy , UintTy } ;
6- use rustc_session:: declare_lint_pass;
76use rustc_span:: Span ;
87
98use clippy_utils:: comparisons;
@@ -12,29 +11,26 @@ use clippy_utils::consts::{ConstEvalCtxt, FullInt};
1211use clippy_utils:: diagnostics:: span_lint;
1312use clippy_utils:: source:: snippet_with_context;
1413
15- declare_clippy_lint ! {
16- /// ### What it does
17- /// Checks for comparisons where the relation is always either
18- /// true or false, but where one side has been upcast so that the comparison is
19- /// necessary. Only integer types are checked.
20- ///
21- /// ### Why is this bad?
22- /// An expression like `let x : u8 = ...; (x as u32) > 300`
23- /// will mistakenly imply that it is possible for `x` to be outside the range of
24- /// `u8`.
25- ///
26- /// ### Example
27- /// ```no_run
28- /// let x: u8 = 1;
29- /// (x as u32) > 300;
30- /// ```
31- #[ clippy:: version = "pre 1.29.0" ]
32- pub INVALID_UPCAST_COMPARISONS ,
33- pedantic,
34- "a comparison involving an upcast which is always true or false"
35- }
14+ use super :: INVALID_UPCAST_COMPARISONS ;
15+
16+ pub ( super ) fn check < ' tcx > (
17+ cx : & LateContext < ' tcx > ,
18+ cmp : BinOpKind ,
19+ lhs : & ' tcx Expr < ' _ > ,
20+ rhs : & ' tcx Expr < ' _ > ,
21+ span : Span ,
22+ ) {
23+ let normalized = comparisons:: normalize_comparison ( cmp, lhs, rhs) ;
24+ let Some ( ( rel, normalized_lhs, normalized_rhs) ) = normalized else {
25+ return ;
26+ } ;
3627
37- declare_lint_pass ! ( InvalidUpcastComparisons => [ INVALID_UPCAST_COMPARISONS ] ) ;
28+ let lhs_bounds = numeric_cast_precast_bounds ( cx, normalized_lhs) ;
29+ let rhs_bounds = numeric_cast_precast_bounds ( cx, normalized_rhs) ;
30+
31+ upcast_comparison_bounds_err ( cx, span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false ) ;
32+ upcast_comparison_bounds_err ( cx, span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true ) ;
33+ }
3834
3935fn numeric_cast_precast_bounds ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> Option < ( FullInt , FullInt ) > {
4036 if let ExprKind :: Cast ( cast_exp, _) = expr. kind {
@@ -68,29 +64,6 @@ fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<
6864 }
6965}
7066
71- fn err_upcast_comparison ( cx : & LateContext < ' _ > , span : Span , expr : & Expr < ' _ > , always : bool ) {
72- if let ExprKind :: Cast ( cast_val, _) = expr. kind {
73- let mut applicability = Applicability :: MachineApplicable ;
74- let ( cast_val_snip, _) = snippet_with_context (
75- cx,
76- cast_val. span ,
77- expr. span . ctxt ( ) ,
78- "the expression" ,
79- & mut applicability,
80- ) ;
81- span_lint (
82- cx,
83- INVALID_UPCAST_COMPARISONS ,
84- span,
85- format ! (
86- "because of the numeric bounds on `{}` prior to casting, this expression is always {}" ,
87- cast_val_snip,
88- if always { "true" } else { "false" } ,
89- ) ,
90- ) ;
91- }
92- }
93-
9467fn upcast_comparison_bounds_err < ' tcx > (
9568 cx : & LateContext < ' tcx > ,
9669 span : Span ,
@@ -103,63 +76,54 @@ fn upcast_comparison_bounds_err<'tcx>(
10376 if let Some ( ( lb, ub) ) = lhs_bounds
10477 && let Some ( norm_rhs_val) = ConstEvalCtxt :: new ( cx) . eval_full_int ( rhs, span. ctxt ( ) )
10578 {
106- if rel == Rel :: Eq || rel == Rel :: Ne {
107- if norm_rhs_val < lb || norm_rhs_val > ub {
108- err_upcast_comparison ( cx, span, lhs, rel == Rel :: Ne ) ;
109- }
110- } else if match rel {
111- Rel :: Lt => {
112- if invert {
113- norm_rhs_val < lb
114- } else {
115- ub < norm_rhs_val
79+ match rel {
80+ Rel :: Eq => {
81+ if norm_rhs_val < lb || ub < norm_rhs_val {
82+ err_upcast_comparison ( cx, span, lhs, false ) ;
11683 }
11784 } ,
118- Rel :: Le => {
119- if invert {
120- norm_rhs_val <= lb
121- } else {
122- ub <= norm_rhs_val
85+ Rel :: Ne => {
86+ if norm_rhs_val < lb || ub < norm_rhs_val {
87+ err_upcast_comparison ( cx, span, lhs, true ) ;
12388 }
12489 } ,
125- Rel :: Eq | Rel :: Ne => unreachable ! ( ) ,
126- } {
127- err_upcast_comparison ( cx, span, lhs, true ) ;
128- } else if match rel {
12990 Rel :: Lt => {
130- if invert {
131- norm_rhs_val >= ub
132- } else {
133- lb >= norm_rhs_val
91+ if ( invert && norm_rhs_val < lb ) || ( !invert && ub < norm_rhs_val ) {
92+ err_upcast_comparison ( cx , span , lhs , true ) ;
93+ } else if ( !invert && norm_rhs_val <= lb ) || ( invert && ub <= norm_rhs_val ) {
94+ err_upcast_comparison ( cx , span , lhs , false ) ;
13495 }
13596 } ,
13697 Rel :: Le => {
137- if invert {
138- norm_rhs_val > ub
139- } else {
140- lb > norm_rhs_val
98+ if ( invert && norm_rhs_val <= lb ) || ( !invert && ub <= norm_rhs_val ) {
99+ err_upcast_comparison ( cx , span , lhs , true ) ;
100+ } else if ( !invert && norm_rhs_val < lb ) || ( invert && ub < norm_rhs_val ) {
101+ err_upcast_comparison ( cx , span , lhs , false ) ;
141102 }
142103 } ,
143- Rel :: Eq | Rel :: Ne => unreachable ! ( ) ,
144- } {
145- err_upcast_comparison ( cx, span, lhs, false ) ;
146104 }
147105 }
148106}
149107
150- impl < ' tcx > LateLintPass < ' tcx > for InvalidUpcastComparisons {
151- fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
152- if let ExprKind :: Binary ( ref cmp, lhs, rhs) = expr. kind {
153- let normalized = comparisons:: normalize_comparison ( cmp. node , lhs, rhs) ;
154- let Some ( ( rel, normalized_lhs, normalized_rhs) ) = normalized else {
155- return ;
156- } ;
157-
158- let lhs_bounds = numeric_cast_precast_bounds ( cx, normalized_lhs) ;
159- let rhs_bounds = numeric_cast_precast_bounds ( cx, normalized_rhs) ;
160-
161- upcast_comparison_bounds_err ( cx, expr. span , rel, lhs_bounds, normalized_lhs, normalized_rhs, false ) ;
162- upcast_comparison_bounds_err ( cx, expr. span , rel, rhs_bounds, normalized_rhs, normalized_lhs, true ) ;
163- }
108+ fn err_upcast_comparison ( cx : & LateContext < ' _ > , span : Span , expr : & Expr < ' _ > , always : bool ) {
109+ if let ExprKind :: Cast ( cast_val, _) = expr. kind {
110+ let mut applicability = Applicability :: MachineApplicable ;
111+ let ( cast_val_snip, _) = snippet_with_context (
112+ cx,
113+ cast_val. span ,
114+ expr. span . ctxt ( ) ,
115+ "the expression" ,
116+ & mut applicability,
117+ ) ;
118+ span_lint (
119+ cx,
120+ INVALID_UPCAST_COMPARISONS ,
121+ span,
122+ format ! (
123+ "because of the numeric bounds on `{}` prior to casting, this expression is always {}" ,
124+ cast_val_snip,
125+ if always { "true" } else { "false" } ,
126+ ) ,
127+ ) ;
164128 }
165129}
0 commit comments