11//! lint on manually implemented checked conversions that could be transformed into `try_from`
22
33use if_chain:: if_chain;
4+ use lazy_static:: lazy_static;
45use rustc:: hir:: * ;
56use rustc:: lint:: { in_external_macro, LateContext , LateLintPass , LintArray , LintContext , LintPass } ;
67use rustc:: { declare_lint_pass, declare_tool_lint} ;
78use rustc_errors:: Applicability ;
89use 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 } ;
1013
1114declare_clippy_lint ! {
1215 /// **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) -
101104struct Conversion < ' a > {
102105 cvt : ConversionType ,
103106 expr_to_cast : & ' a Expr ,
104- to_type : Option < String > ,
107+ to_type : Option < Symbol > ,
105108}
106109
107110/// The kind of conversion that is checked
@@ -137,8 +140,8 @@ impl<'a> Conversion<'a> {
137140 }
138141
139142 /// 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 {
142145 cvt,
143146 expr_to_cast,
144147 to_type : Some ( to_type) ,
@@ -157,13 +160,13 @@ impl<'a> Conversion<'a> {
157160
158161impl ConversionType {
159162 /// 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) {
162165 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) {
165168 Some ( ConversionType :: SignedToUnsigned )
166- } else if SIGNED_TYPES . contains ( & to) {
169+ } else if SINTS . contains ( & to) {
167170 Some ( ConversionType :: SignedToSigned )
168171 } else {
169172 None
@@ -179,10 +182,10 @@ fn check_upper_bound(expr: &Expr) -> Option<Conversion<'_>> {
179182 if_chain ! {
180183 if let ExprKind :: Binary ( ref op, ref left, ref right) = & expr. node;
181184 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 ) ;
183186
184187 then {
185- Conversion :: try_new( candidate, & from, to)
188+ Conversion :: try_new( candidate, from, to)
186189 } else {
187190 None
188191 }
@@ -219,31 +222,31 @@ fn check_lower_bound_zero<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Co
219222
220223/// Check for `expr >= (to_type::min_value() as from_type)`
221224fn 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)
224227 } else {
225228 None
226229 }
227230}
228231
229232/// 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 ) > {
231234 // `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 ! {
233236 // to_type::maxmin_value(), from_type
234237 if let ExprKind :: Cast ( ref limit, ref from_type) = & expr. node;
235238 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) ;
237240
238241 then {
239- Some ( ( limit, from_type_str . to_string ( ) ) )
242+ Some ( ( limit, from_sym ) )
240243 } else {
241244 None
242245 }
243246 } ;
244247
245248 // `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 ( || {
247250 if_chain ! {
248251 // `from_type::from, to_type::maxmin_value()`
249252 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
252255 if let limit = & args[ 0 ] ;
253256 // `from_type::from`
254257 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) ;
256259
257260 then {
258- Some ( ( limit, from_type ) )
261+ Some ( ( limit, from_sym ) )
259262 } else {
260263 None
261264 }
@@ -282,33 +285,33 @@ fn get_types_from_cast(expr: &Expr, func: &str, types: &[&str]) -> Option<(Strin
282285}
283286
284287/// 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 > {
286289 if_chain ! {
287290 if let QPath :: TypeRelative ( ref ty, ref path) = & path;
288291 if path. ident. name == function;
289292 if let TyKind :: Path ( QPath :: Resolved ( None , ref tp) ) = & ty. node;
290293 if let [ int] = & * tp. segments;
291- let name = int. ident. as_str ( ) . get ( ) ;
294+ let name = int. ident. name ;
292295 if candidates. contains( & name) ;
293296
294297 then {
295- Some ( name. to_string ( ) )
298+ Some ( name)
296299 } else {
297300 None
298301 }
299302 }
300303}
301304
302305/// 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 > {
304307 if_chain ! {
305308 if let QPath :: Resolved ( _, ref path) = * path;
306309 if let [ ty] = & * path. segments;
307310
308311 then {
309- INT_TYPES
312+ INTS
310313 . iter( )
311- . find( |c| ( & ty. ident. name) == * c)
314+ . find( |c| ty. ident. name == * * c)
312315 . cloned( )
313316 } else {
314317 None
@@ -333,8 +336,19 @@ fn normalize_le_ge<'a>(op: &'a BinOp, left: &'a Expr, right: &'a Expr) -> Option
333336 }
334337}
335338
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