1
1
//! lint on manually implemented checked conversions that could be transformed into `try_from`
2
2
3
3
use if_chain:: if_chain;
4
+ use lazy_static:: lazy_static;
4
5
use rustc:: hir:: * ;
5
6
use rustc:: lint:: { in_external_macro, LateContext , LateLintPass , LintArray , LintContext , LintPass } ;
6
7
use rustc:: { declare_lint_pass, declare_tool_lint} ;
7
8
use rustc_errors:: Applicability ;
8
9
use syntax:: ast:: LitKind ;
9
- use crate :: utils:: { span_lint_and_sugg, snippet_with_applicability, SpanlessEq } ;
10
+ use syntax:: symbol:: Symbol ;
11
+
12
+ use crate :: utils:: { snippet_with_applicability, span_lint_and_sugg, sym, SpanlessEq } ;
10
13
11
14
declare_clippy_lint ! {
12
15
/// **What it does:** Checks for explicit bounds checking when casting.
@@ -101,7 +104,7 @@ fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr, right: &'a Expr) -
101
104
struct Conversion < ' a > {
102
105
cvt : ConversionType ,
103
106
expr_to_cast : & ' a Expr ,
104
- to_type : Option < String > ,
107
+ to_type : Option < Symbol > ,
105
108
}
106
109
107
110
/// The kind of conversion that is checked
@@ -137,8 +140,8 @@ impl<'a> Conversion<'a> {
137
140
}
138
141
139
142
/// Try to construct a new conversion if the conversion type is valid
140
- fn try_new < ' b > ( expr_to_cast : & ' a Expr , from_type : & ' b str , to_type : String ) -> Option < Conversion < ' a > > {
141
- ConversionType :: try_new ( from_type, & to_type) . map ( |cvt| Conversion {
143
+ fn try_new < ' b > ( expr_to_cast : & ' a Expr , from_type : Symbol , to_type : Symbol ) -> Option < Conversion < ' a > > {
144
+ ConversionType :: try_new ( from_type, to_type) . map ( |cvt| Conversion {
142
145
cvt,
143
146
expr_to_cast,
144
147
to_type : Some ( to_type) ,
@@ -157,13 +160,13 @@ impl<'a> Conversion<'a> {
157
160
158
161
impl ConversionType {
159
162
/// Creates a conversion type if the type is allowed & conversion is valid
160
- fn try_new ( from : & str , to : & str ) -> Option < Self > {
161
- if UNSIGNED_TYPES . contains ( & from) {
163
+ fn try_new ( from : Symbol , to : Symbol ) -> Option < Self > {
164
+ if UINTS . contains ( & from) {
162
165
Some ( ConversionType :: FromUnsigned )
163
- } else if SIGNED_TYPES . contains ( & from) {
164
- if UNSIGNED_TYPES . contains ( & to) {
166
+ } else if SINTS . contains ( & from) {
167
+ if UINTS . contains ( & to) {
165
168
Some ( ConversionType :: SignedToUnsigned )
166
- } else if SIGNED_TYPES . contains ( & to) {
169
+ } else if SINTS . contains ( & to) {
167
170
Some ( ConversionType :: SignedToSigned )
168
171
} else {
169
172
None
@@ -179,10 +182,10 @@ fn check_upper_bound(expr: &Expr) -> Option<Conversion<'_>> {
179
182
if_chain ! {
180
183
if let ExprKind :: Binary ( ref op, ref left, ref right) = & expr. node;
181
184
if let Some ( ( candidate, check) ) = normalize_le_ge( op, left, right) ;
182
- if let Some ( ( from, to) ) = get_types_from_cast( check, " max_value" , INT_TYPES ) ;
185
+ if let Some ( ( from, to) ) = get_types_from_cast( check, * sym :: max_value, & * INTS ) ;
183
186
184
187
then {
185
- Conversion :: try_new( candidate, & from, to)
188
+ Conversion :: try_new( candidate, from, to)
186
189
} else {
187
190
None
188
191
}
@@ -219,31 +222,31 @@ fn check_lower_bound_zero<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Co
219
222
220
223
/// Check for `expr >= (to_type::min_value() as from_type)`
221
224
fn check_lower_bound_min < ' a > ( candidate : & ' a Expr , check : & ' a Expr ) -> Option < Conversion < ' a > > {
222
- if let Some ( ( from, to) ) = get_types_from_cast ( check, " min_value" , SIGNED_TYPES ) {
223
- Conversion :: try_new ( candidate, & from, to)
225
+ if let Some ( ( from, to) ) = get_types_from_cast ( check, * sym :: min_value, & * SINTS ) {
226
+ Conversion :: try_new ( candidate, from, to)
224
227
} else {
225
228
None
226
229
}
227
230
}
228
231
229
232
/// Tries to extract the from- and to-type from a cast expression
230
- fn get_types_from_cast ( expr : & Expr , func : & str , types : & [ & str ] ) -> Option < ( String , String ) > {
233
+ fn get_types_from_cast ( expr : & Expr , func : Symbol , types : & [ Symbol ] ) -> Option < ( Symbol , Symbol ) > {
231
234
// `to_type::maxmin_value() as from_type`
232
- let call_from_cast: Option < ( & Expr , String ) > = if_chain ! {
235
+ let call_from_cast: Option < ( & Expr , Symbol ) > = if_chain ! {
233
236
// to_type::maxmin_value(), from_type
234
237
if let ExprKind :: Cast ( ref limit, ref from_type) = & expr. node;
235
238
if let TyKind :: Path ( ref from_type_path) = & from_type. node;
236
- if let Some ( from_type_str ) = int_ty_to_str ( from_type_path) ;
239
+ if let Some ( from_sym ) = int_ty_to_sym ( from_type_path) ;
237
240
238
241
then {
239
- Some ( ( limit, from_type_str . to_string ( ) ) )
242
+ Some ( ( limit, from_sym ) )
240
243
} else {
241
244
None
242
245
}
243
246
} ;
244
247
245
248
// `from_type::from(to_type::maxmin_value())`
246
- let limit_from: Option < ( & Expr , String ) > = call_from_cast. or_else ( || {
249
+ let limit_from: Option < ( & Expr , Symbol ) > = call_from_cast. or_else ( || {
247
250
if_chain ! {
248
251
// `from_type::from, to_type::maxmin_value()`
249
252
if let ExprKind :: Call ( ref from_func, ref args) = & expr. node;
@@ -252,10 +255,10 @@ fn get_types_from_cast(expr: &Expr, func: &str, types: &[&str]) -> Option<(Strin
252
255
if let limit = & args[ 0 ] ;
253
256
// `from_type::from`
254
257
if let ExprKind :: Path ( ref path) = & from_func. node;
255
- if let Some ( from_type ) = get_implementing_type( path, INT_TYPES , " from" ) ;
258
+ if let Some ( from_sym ) = get_implementing_type( path, & * INTS , * sym :: from) ;
256
259
257
260
then {
258
- Some ( ( limit, from_type ) )
261
+ Some ( ( limit, from_sym ) )
259
262
} else {
260
263
None
261
264
}
@@ -282,33 +285,33 @@ fn get_types_from_cast(expr: &Expr, func: &str, types: &[&str]) -> Option<(Strin
282
285
}
283
286
284
287
/// Gets the type which implements the called function
285
- fn get_implementing_type ( path : & QPath , candidates : & [ & str ] , function : & str ) -> Option < String > {
288
+ fn get_implementing_type ( path : & QPath , candidates : & [ Symbol ] , function : Symbol ) -> Option < Symbol > {
286
289
if_chain ! {
287
290
if let QPath :: TypeRelative ( ref ty, ref path) = & path;
288
291
if path. ident. name == function;
289
292
if let TyKind :: Path ( QPath :: Resolved ( None , ref tp) ) = & ty. node;
290
293
if let [ int] = & * tp. segments;
291
- let name = int. ident. as_str ( ) . get ( ) ;
294
+ let name = int. ident. name ;
292
295
if candidates. contains( & name) ;
293
296
294
297
then {
295
- Some ( name. to_string ( ) )
298
+ Some ( name)
296
299
} else {
297
300
None
298
301
}
299
302
}
300
303
}
301
304
302
305
/// Gets the type as a string, if it is a supported integer
303
- fn int_ty_to_str ( path : & QPath ) -> Option < & str > {
306
+ fn int_ty_to_sym ( path : & QPath ) -> Option < Symbol > {
304
307
if_chain ! {
305
308
if let QPath :: Resolved ( _, ref path) = * path;
306
309
if let [ ty] = & * path. segments;
307
310
308
311
then {
309
- INT_TYPES
312
+ INTS
310
313
. iter( )
311
- . find( |c| ( & ty. ident. name) == * c)
314
+ . find( |c| ty. ident. name == * * c)
312
315
. cloned( )
313
316
} else {
314
317
None
@@ -333,8 +336,19 @@ fn normalize_le_ge<'a>(op: &'a BinOp, left: &'a Expr, right: &'a Expr) -> Option
333
336
}
334
337
}
335
338
336
- const UNSIGNED_TYPES : & [ & str ] = & [ "u8" , "u16" , "u32" , "u64" , "u128" , "usize" ] ;
337
- const SIGNED_TYPES : & [ & str ] = & [ "i8" , "i16" , "i32" , "i64" , "i128" , "isize" ] ;
338
- const INT_TYPES : & [ & str ] = & [
339
- "u8" , "u16" , "u32" , "u64" , "u128" , "usize" , "i8" , "i16" , "i32" , "i64" , "i128" , "isize" ,
340
- ] ;
339
+ lazy_static ! {
340
+ static ref UINTS : [ Symbol ; 5 ] = [ * sym:: u8 , * sym:: u16 , * sym:: u32 , * sym:: u64 , * sym:: usize ] ;
341
+ static ref SINTS : [ Symbol ; 5 ] = [ * sym:: i8 , * sym:: i16 , * sym:: i32 , * sym:: i64 , * sym:: isize ] ;
342
+ static ref INTS : [ Symbol ; 10 ] = [
343
+ * sym:: u8 ,
344
+ * sym:: u16 ,
345
+ * sym:: u32 ,
346
+ * sym:: u64 ,
347
+ * sym:: usize ,
348
+ * sym:: i8 ,
349
+ * sym:: i16 ,
350
+ * sym:: i32 ,
351
+ * sym:: i64 ,
352
+ * sym:: isize
353
+ ] ;
354
+ }
0 commit comments