@@ -9,15 +9,17 @@ use rustc_ast as ast;
9
9
use rustc_data_structures:: fx:: FxHashSet ;
10
10
use rustc_hir as hir;
11
11
use rustc_lint:: { LateContext , LateLintPass } ;
12
+ use rustc_middle:: ty:: Ty ;
12
13
use rustc_session:: impl_lint_pass;
13
14
use rustc_span:: source_map:: { Span , Spanned } ;
14
15
15
16
const HARD_CODED_ALLOWED : & [ & str ] = & [
16
17
"f32" ,
17
18
"f64" ,
18
19
"std::num::Saturating" ,
19
- "std::string::String" ,
20
20
"std::num::Wrapping" ,
21
+ "std::string::String" ,
22
+ "&str" ,
21
23
] ;
22
24
23
25
#[ derive( Debug ) ]
@@ -60,15 +62,14 @@ impl ArithmeticSideEffects {
60
62
}
61
63
62
64
/// Checks if the given `expr` has any of the inner `allowed` elements.
63
- fn is_allowed_ty ( & self , cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) -> bool {
64
- self . allowed . contains (
65
- cx. typeck_results ( )
66
- . expr_ty ( expr)
67
- . to_string ( )
68
- . split ( '<' )
69
- . next ( )
70
- . unwrap_or_default ( ) ,
71
- )
65
+ fn is_allowed_ty ( & self , ty : Ty < ' _ > ) -> bool {
66
+ self . allowed
67
+ . contains ( ty. to_string ( ) . split ( '<' ) . next ( ) . unwrap_or_default ( ) )
68
+ }
69
+
70
+ // For example, 8i32 or &i64::MAX.
71
+ fn is_integral ( ty : Ty < ' _ > ) -> bool {
72
+ ty. peel_refs ( ) . is_integral ( )
72
73
}
73
74
74
75
// Common entry-point to avoid code duplication.
@@ -82,24 +83,13 @@ impl ArithmeticSideEffects {
82
83
/// * Is `expr` is a literal integer reference like `&199`, returns the literal integer without
83
84
/// references.
84
85
/// * If `expr` is anything else, returns `None`.
85
- fn literal_integer < ' expr , ' tcx > (
86
- cx : & LateContext < ' tcx > ,
87
- expr : & ' expr hir:: Expr < ' tcx > ,
88
- ) -> Option < & ' expr hir:: Expr < ' tcx > > {
89
- let expr_refs = cx. typeck_results ( ) . expr_ty ( expr) . peel_refs ( ) ;
90
-
91
- if !expr_refs. is_integral ( ) {
92
- return None ;
93
- }
94
-
86
+ fn literal_integer < ' expr , ' tcx > ( expr : & ' expr hir:: Expr < ' tcx > ) -> Option < & ' expr hir:: Expr < ' tcx > > {
95
87
if matches ! ( expr. kind, hir:: ExprKind :: Lit ( _) ) {
96
88
return Some ( expr) ;
97
89
}
98
-
99
90
if let hir:: ExprKind :: AddrOf ( .., inn) = expr. kind && let hir:: ExprKind :: Lit ( _) = inn. kind {
100
91
return Some ( inn)
101
92
}
102
-
103
93
None
104
94
}
105
95
@@ -128,14 +118,21 @@ impl ArithmeticSideEffects {
128
118
) {
129
119
return ;
130
120
} ;
131
- if self . is_allowed_ty ( cx, lhs) || self . is_allowed_ty ( cx, rhs) {
121
+ let lhs_ty = cx. typeck_results ( ) . expr_ty ( lhs) ;
122
+ let rhs_ty = cx. typeck_results ( ) . expr_ty ( rhs) ;
123
+ let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty;
124
+ if lhs_and_rhs_have_the_same_ty && self . is_allowed_ty ( lhs_ty) && self . is_allowed_ty ( rhs_ty) {
132
125
return ;
133
126
}
134
- let has_valid_op = match ( Self :: literal_integer ( cx, lhs) , Self :: literal_integer ( cx, rhs) ) {
135
- ( None , None ) => false ,
136
- ( None , Some ( local_expr) ) => Self :: has_valid_op ( op, local_expr) ,
137
- ( Some ( local_expr) , None ) => Self :: has_valid_op ( op, local_expr) ,
138
- ( Some ( _) , Some ( _) ) => true ,
127
+ let has_valid_op = if Self :: is_integral ( lhs_ty) && Self :: is_integral ( rhs_ty) {
128
+ match ( Self :: literal_integer ( lhs) , Self :: literal_integer ( rhs) ) {
129
+ ( None , None ) => false ,
130
+ ( None , Some ( local_expr) ) => Self :: has_valid_op ( op, local_expr) ,
131
+ ( Some ( local_expr) , None ) => Self :: has_valid_op ( op, local_expr) ,
132
+ ( Some ( _) , Some ( _) ) => true ,
133
+ }
134
+ } else {
135
+ false
139
136
} ;
140
137
if !has_valid_op {
141
138
self . issue_lint ( cx, expr) ;
0 commit comments